oneToMany copy between different entityManagers - jpa-2.0

I have a utility to copy entities between two different databases using two entity managers.
Query q = em1.createQuery("SELECT o FROM Holder o WHERE o.id=1");
Holder holder = (List<Holder>) q.getSingleResult();
em1.clear();
em2.getTransaction().begin();
em2.merge(holder);
em2.getTransaction().commit();
All works fine except oneToMany relations:
#Entity
public class Holder{
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "HOLDER_ID")
private Set<Piece> pieces;
}
#Entity
public class Piece{
//No mapped by to holder
}
The result of the operation is that holder is persisted ok and pieces are persisted as well BUT HOLDER_ID is null.
If I explicit a mapped by holder in Piece the joincolumn is copied but I can't change the model to be bidirectional.
Any ideas of what can be wrong? Detaching and merging in the same entityManager works fine too.
UPDATE: The sql generated does not contains HOLDER_ID update so 'it fails' too in the same entityManager.
(I'm using Hibernate as JPA provider).

Ok, I found out that the sql generated if the tables are empty is
1/ Insert for Holder
2/ Insert for each Piece
3/ Update to setup Holder_id in each Piece
But if the tables contains Holder but not pieces
1/ Insert for each Piece
That's the reason pieces losses reference to Holder.

Related

Extending SimpleNeo4jRepository in SDN 6

In SDN+OGM I used the following method to extend the base repository with additional functionality, specifically I want a way to find or create entities of different types (labels):
#NoRepositoryBean
public class MyBaseRepository<T> extends SimpleNeo4jRepository<T, String> {
private final Class<T> domainClass;
private final Session session;
public SpacBaseRepository(Class<T> domainClass, Session session) {
super(domainClass, session);
this.domainClass = domainClass;
this.session = session;
}
#Transactional
public T findOrCreateByName(String name) {
HashMap<String, String> params = new HashMap<>();
params.put("name", name);
params.put("uuid", UUID.randomUUID().toString());
// we do not use queryForObject in case of broken data with non-unique names
return this.session.query(
domainClass,
String.format("MERGE (x:%s {name:$name}) " +
"ON CREATE SET x.creationDate = timestamp(), x.uuid = $uuid " +
"RETURN x", domainClass.getSimpleName()),
params
).iterator().next();
}
}
This makes it so that I can simply add findOrCreateByName to any of my repository interfaces without the need to duplicate a query annotation.
I know that SDN 6 supports the automatic creation of a UUID very nicely through #GeneratedValue(UUIDStringGenerator.class) but I also want to add the creation date in a generic way. The method above allows to do that in OGM but in SDN the API changed and I am a bit lost.
Well, sometimes it helps to write down things. I figured out that the API did not change that much. Basically the Session is replaced with Neo4jOperations and the Class is replaced with Neo4jEntityInformation.
But even more important is that SDN 6 has #CreatedDate which makes my entire custom code redundant.

Acumatica - Cross Referencing

My DAC and tables are defined as follows
Data structure
ParentTableDAC (FormView)
ChildDac1 (TAb1/Grid)
ChildDac2 (Tab2/Grid)
in ChildDAc2, ChildDAc1ID need to be shown as Selector, How this can be done?
We are facing issue if Data is not saved for Parent/ChildDAc1 then it is not available to ChildDAc2 Lookup
Update -
Business Scenario -
A work item has Multiple Task and multiple Steps to perform the work item.
now WORKITEMDAC is a Parent
TASKDAC and STEPDAC are the Child of the Parent WORKITEMDAC.
OK till yet everything is ok and Usual..
Now each step is suppose to be linked with the Task of the Parent WORKITEM.
SO in STEPS Grid a Selector is required to select the TASK.
Here I have proper Parent child relationship there is no issue with that,I have only one issue that is, I can select only the TASK which was already saved with the Parent WORKITEM, unsaved Tasks are not displayed in the selector.
SO My Question was, do we have any way to get the Task in the PXSelector query which is not yet saved?
Following Selector is used on STEPDAC on TaskID Column -
[PXSelector(typeof(Search<TASKDAC.TaskID, Where<TASKDAC.taskID, Equal<Current>>>), typeof(TASKDAC.taskCD), SubstituteKey = typeof(TASKDAC.taskCD))]
Note - TaskID column in TASKDAC is identity column and this DAC has WorkItemID defined as PArent.
Update
Thanks for updating with more detail. Leaving the original response below for those that may need it regarding parent/child.
I've never seen the selector defined with reference to Current<> and no Current WHAT. To be honest, I'm surprised it compiled. "Where Field = Current View Field" directs the selector to limit results to only values associated to the Current value of whatever field you specified, and it is retrieved from the "ViewName.Current" record in the graph. Your where clause does not tell it what "current" to match. Since you direct the selector to Search, I suspect that this is causing the selector to be unable to find a matching record and short-circuiting the save of the result for that field.
It sounds like TASKDAC is a "master data" type record, defining all possible tasks to be performed. Therefore, TaskID is not a key field in STEPDAC but rather a key field in TASKDAC. If you want to select "any" task, you don't need the where clause at all.
[PXSelector(
typeof(TASKDAC.TaskID),
typeof(TASKDAC.taskCD),
SubstituteKey = typeof(TASKDAC.taskCD)
)]
Let's assume for a moment that you designate a WORKITEMDAC.WorkOrderType that is used to filter acceptable tasks by the same field. (Only repair tasks can be assigned to a repair WorkOrderType, assembly to an assembly WorkOrderType, etc.) In this case, you would use the syntax you stated, but you would designate Where<TASKDAC.WorkOrderType, Equal<Current<WORKITEMDAC.WorkOrderType>>. If the task is limited to something in the STEPDAC instead, just swap out WORKITEMDAC with the STEPDAC field in the example below.
[PXSelector(
typeof(Search<TASKDAC.TaskID,
Where<TASKDAC.WorkOrderType, Equal<Current<WORKITEMDAC.WorkOrderType>>>>),
typeof(TASKDAC.taskCD),
SubstituteKey = typeof(TASKDAC.taskCD)
)]
Please update your PXSelector and advise if that fixes the issue or what error you get next.
Original Response
With so little to your question, the nature of your question is very unclear. It sounds like you are attempting to do something that should perhaps take a different approach. The definition of a selector should not impact the saving of a field, but the structure of a parent child relationship is critical to define properly. As such, it seems very odd that you would have a Child ID that differs from the parent and that it would be used in a selector.
Typically, the child DAC shares an ID with the parent DAC. We often define a LineNbr field in the child which is given a value by PXLineNbrAttribute, and the Key fields would be ID + LineNbr to identify a specific child record. We also set SyncPosition = true in the ASPX document on the grid so that the user interface stays completely sync'd with whichever record the user has selected in the grid. Parent Child relationships can be daisy chained, such as with SOOrder -> SOLine -> SOLineSplit, but ultimately, the ID field of a child is not a selector... the ID of the parent is.
Think of a selector as a means of looking up master data. Master data may be related to other data, but it would not have a parent in most cases. There are exceptions, but let's keep it simple. A purchase order, for instance, would not have parent, and the key field would be a common selector field. However, since a child must always relate to its parent and cannot change its parent, the ID of the child field would not be a selector. Other tables in Acumatica would refer back to some field or combination of fields to relate to the data of a child DAC.
From the T210 training guides, I stripped away a lot to show just this point.
RSSVRepairPrice - Parent
using System;
using PX.Data;
namespace PhoneRepairShop
{
[PXCacheName("Repair Price")]
public class RSSVRepairPrice : IBqlTable
{
#region PriceID
[PXDBIdentity]
public virtual int? PriceID { get; set; }
public abstract class priceID : PX.Data.BQL.BqlInt.Field<priceID> { }
#endregion
#region ServiceID
[PXDBInt(IsKey = true)]
[PXDefault]
[PXUIField(DisplayName = "Service", Required = true)]
[PXSelector(
typeof(Search<RSSVRepairService.serviceID>),
typeof(RSSVRepairService.serviceCD),
typeof(RSSVRepairService.description),
DescriptionField = typeof(RSSVRepairService.description),
SelectorMode = PXSelectorMode.DisplayModeText)]
public virtual int? ServiceID { get; set; }
public abstract class serviceID : PX.Data.BQL.BqlInt.Field<serviceID> { }
#endregion
#region RepairItemLineCntr
[PXDBInt()]
[PXDefault(0)]
public virtual Int32? RepairItemLineCntr { get; set; }
public abstract class repairItemLineCntr : PX.Data.BQL.BqlInt.Field<repairItemLineCntr> { }
#endregion
}
}
RSSVRepairItem - Child
using System;
using PX.Data;
using PX.Objects.IN;
using PX.Data.BQL.Fluent;
namespace PhoneRepairShop
{
[PXCacheName("Repair Item")]
public class RSSVRepairItem : IBqlTable
{
#region ServiceID
[PXDBInt(IsKey = true)]
[PXDBDefault(typeof(RSSVRepairPrice.serviceID))]
[PXParent(
typeof(SelectFrom<RSSVRepairPrice>.
Where<RSSVRepairPrice.serviceID.IsEqual<
RSSVRepairItem.serviceID.FromCurrent>>
))]
public virtual int? ServiceID { get; set; }
public abstract class serviceID : PX.Data.BQL.BqlInt.Field<serviceID> { }
#endregion
#region LineNbr
[PXDBInt(IsKey = true)]
[PXLineNbr(typeof(RSSVRepairPrice.repairItemLineCntr))]
[PXUIField(DisplayName = "Line Nbr.", Visible = false)]
public virtual int? LineNbr { get; set; }
public abstract class lineNbr : PX.Data.BQL.BqlInt.Field<lineNbr> { }
#endregion
}
}
In the parent, notice the use of PXDBIdentityAttribute which specifies that the record identity is set by the database in PriceID. The "ID" field used by the child is taken from the ServiceID field which is defined as a selector for another master table. The use of IsKey = true on PXDBIntAttribute tells Acumatica that it can find the unique record by the combination of all the fields marked IsKey = true. (Note that the actual training guide includes another field as part of the key, but I simplified the example here.) Also notice the use of a PDXBInt field that has a default of 0 to be used as a Line Counter. (RepairItemLineCtr)
Now, in the child, notice that the key field of the parent is defined again in the DAC, but without the selector. The PXParentAttribute defines the relationship back to the parent DAC, and the field value is defaulted in from that parent. This is what causes the value to be saved in the record automatically. It also associates the relationship so that deleting the parent will delete the child as well. Notice the use of PXLineNbrAttribute to autoincrement the field of the parent DAC and set the value in the LineNbr field. It is the combination of these 2 fields that points you to the exact record.
There are cases where Acumatica uses the NoteID field (a unique GUID value) to identify a record of a child DAC, but this is a bit more complex. You can see it in the relationship of INItemPlan (Demand) to Purchase Orders.
If you are having trouble with Parent-Child (Master-Detail) relationships, I'd highly recommend reviewing the T210 training course.
To refer the unsaved data use the ISDirty =true on PXSelector.
also to save the Identity key valueof the unsaved data at referenced place, use [PXDBDefault()]

How to remove a many-to-many relationship with spring-data-neo4j?

I have the following entities:
#NodeEntity(label = "A")
public class A {
#Property(name = "something")
private String someProperty;
//... getters and setters
}
#NodeEntity(label = "B")
public class B {
#Property(name = "someOtherThing")
private String otherProperty;
//... getters and setters
}
#RelationshipEntity(type = "AB")
public class AB {
#StartNode
private A start;
#EndNode
private B end;
#Property(name = "evenOtherThing")
private String prop;
//... getters and setters
}
So, in this situation I have (:A)-[:AB]->(:B). I can have several ABs (meaning I can connect A to B several times, having different properties each time).
With that configuration I can save AB instances without problems, but when it comes to deleting just the relationship, I couldn't find a way to do so, using the spring-data-neo4j methods.
Things that I tried:
1- Custom query:
#Repository
public interface ABRepository extends GraphRepository<AB> {
#Query("MATCH (a:A)-[ab:AB]->(b:B) WHERE a.something={something} DELETE ab")
void deleteBySomething(#Param("something") String something);
}
Usage:
#Autowired
ABRepository repository;
//...
repository.deleteBySomething(something);
It didn't work as expected. The A node is removed altogether with the AB relationship. If I run the query directly at the database, it works as expected.
2- Delete from the repository:
#Repository
public interface ABRepository extends GraphRepository<AB> {
#Query("MATCH (a:A)-[ab:AB]->(b:B) WHERE a.something={something} RETURN a,ab,b")
Iterable<AB> findBySomething(#Param("something") String something);
}
Usage:
Iterable<AB> it = repository.findBySomething(something);
repository.delete(it);
Same stuff. The nodes are removed. I tried to iterate over the Iterable<AB> and remove the relationships one by one, without success as well.
3- Nulling the references of A and B inside AB and saving AB:
Same code of the repository, with a different usage:
Iterable<AB> it = repository.findBySomething(something);
for (AB ab : it) {
ab.setA(null);
ab.setB(null);
}
repository.save(it);
Here I'm just trying random stuff. It didn't work as expected. The framework rises an exception stating that the start and end nodes can't be null.
So, what am I doing wrong? What does it take to remove a simple relationship from the database using spring-data-neo4j, without removing the linking nodes?
For the record: my neo4j database is v.3.0.4 and my spring-data-neo4j is v.4.1.4.RELEASE. Running Java 8.
In the end the problem was a sum of two factors.
First: not mentioned in the question, but the way I saved the AB entity wasn't ideal. I was using repository.save(ab) directly, and that can make the framework do some magic with the A and B entities inside. To save just the relationship, without touching the related entities, the repository.save(ab, 0) should be used.
Second: removing entities using a custom query is intuitively faster than fetching the entities and then removing them, so using that approach was my first goal. And here again I was confused by some magic behind the scenes, better described at this question: Spring Data Neo4j 4returning cached results?
In summary, after removing entities or relationships using custom queries, I should clear the session:
#Autowired
Session session;
//...
repository.deleteBySomething(something);
session.clear();
These two tweaks fixed the weird behavior I was having with the framework.

Doctrine - I'm getting Entity class instead of Repository class

I create instance of entity manager
$this->em = Connection::MainMySql()->GetEntityManager();
After some queries I try to get object from a Repository class.
$usersArray = $this->em->createQueryBuilder()
->select("us")
->from('Model\Repo\mytables\User', "us")
->where("us.idUser = :idUser")
->setParameter("idUser", $idUser)
->getQuery()
->execute();
Why do I then get list of objects of class Model\Entity\mytables\User instead of Model\Repo\mytables\User even after I specify desired class in from(...) section?
In fact, a repository cannot be used as a representation of a database entry.
In other words, Repositories should contain methods to retrieve/create/update/delete database entries represented by entities.
This is why the EntityManager is called Entity Manager, it manages Entities and not Repository classes.
For instance, you can perfectly do:
// Return an instance of the Repository Model\Repo\mytables\User
$repository = $this->em->getRepository('Model\Entity\mytables\User');
// The repository is used to create the QueryBuilder, so the from statement is already filled by doctrine as model\Entity\mytables\User
$query = $repository->createQueryBuilder('u')
// ...
This is also why you can do:
$repository = $this->em->getRepository('Model\Entity\mytables\User');
// Return all entries of the 'users' table as Model\Entity\mytables\User instances
$users = $repository->findAll();
I'm surprised that the from statement of your query doesn't produce an error such as "Model\Entity\mytables\User is not a valid entity".
Also, your structure looks confusing, you must differentiate properly Repositories (the Models) from Entities in order to use them according to their respective roles.

What's the lazy strategy and how does it work?

I have a problem. I'm learning JPA. I'm using embedded OpenEJB container in unit tests, but only working is #OneToMany(fetch=EAGER). Otherwise is the collection allways null. I haven't found, how the lazy strategy works, how the container fills the data and in which circumstances triggers the container the loading action?
I have read, that the action triggers when the getter is being called. But when I have the code:
#OneToMany(fetch = LAZY, mappedBy="someField")
private Set<AnotherEntities> entities = new Set<AnotherEntities>();
...
public Set<AnotherEntities> getEntities() {
return entities;
}
I'm always getting null. I thing, the LAZY strategy cannot be tested with embedded container. The problem might be also in the bidirectional relation.
Does have anybody else similar expiriences with the JPA testing?
Attachments
The real test case with setup:
#RunWith(UnitilsJUnit4TestClassRunner.class)
#DataSet("dataSource.xml")
public class UnitilsCheck extends UnitilsJUnit4 {
private Persister prs;
public UnitilsCheck() {
Throwable err = null;
try {
Class.forName("org.hsqldb.jdbcDriver").newInstance();
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
props.put("ds", "new://Resource?type=DataSource");
props.put("ds.JdbcDriver", "org.hsqldb.jdbcDriver");
props.put("ds.JdbcUrl", "jdbc:hsqldb:mem:PhoneBookDB");
props.put("ds.UserName", "sa");
props.put("ds.Password", "");
props.put("ds.JtaManaged", "true");
Context context = new InitialContext(props);
prs = (Persister) context.lookup("PersisterImplRemote");
}
catch (Throwable e) {
e.printStackTrace();
err = e;
}
TestCase.assertNull(err);
}
#Test
public void obtainNickNamesLazily() {
TestCase.assertNotNull(prs);
PersistableObject po = prs.findByPrimaryKey("Ferenc");
TestCase.assertNotNull(po);
Collection<NickNames> nicks = po.getNickNames();
TestCase.assertNotNull(nicks);
TestCase.assertEquals("[Nick name: Kutyafája, belongs to Ferenc]", nicks.toString());
}
}
The bean Presister is the bean mediating access to the entity beans. The crucial code of class follows:
#PersistenceUnit(unitName="PhonePU")
protected EntityManagerFactory emf;
public PhoneBook findByPrimaryKey(String name) {
EntityManager em = emf.createEntityManager();
PhoneBook phonebook = (PhoneBook)em.find(PhoneBook.class, name);
em.close();
return phonebook;
}
Entity PhoneBook is one line of phone book (also person). One person can have zero or more nick names. With EAGER strategy it works. With LAZY the collection is allways null. May be the problem is in the detaching of objects. (See OpenEJB - JPA Concepts, part Caches and detaching.) But in the manual is written, that the collection can be sometimes (more like manytimes) empty, but not null.
The problem is in the life cycle of an entity. (Geronimo uses OpenJPA, so le't see OpenJPA tutorial, part Entity Lifecycle Management.) The application uses container managed transactions. Each method call on the bean Persiser runs in an own transation. And the persistency context depends on the transaction. The entity is disconnected from its context at the end of the transaction, thus at the end of the method. I tried to get the entity and on second line in the same method to get the collection of nick names and it worked. So the problem was identifyed: I cannot get additionally any entity data from the data store without re-attaching the entity to some persistency context. The entity is re-attached by the EntityManager.merge() method.
The code needs more correctures. Because the entity cannot obtain the EntityManager reference and re-attach itself, the method returning nick names must be moved to the Persister class. (The comment Heureka marks the critical line re-attaching the entity.)
public Collection<NickNames> getNickNamesFor(PhoneBook pb) {
//emf is an EntityManagerFactory reference
EntityManager em = emf.createEntityManager();
PhoneBook pb = em.merge(pb); //Heureka!
Collection<NickNames> nicks = pb.getNickNames();
em.close();
return nicks;
}
The collection is then obtained in this way:
//I have a PhoneBook instance pb
//pb.getNickNames() returns null only
//I have a Persister instance pe
nicks = pe.getNickNames(pb);
That's all.
You can have a look at my second question concerning this topic I'have asked on this forum. It is the qustion OpenJPA - lazy fetching does not work.
How I would write the code
#Entity
public class MyEntity {
#OneToMany(fetch = LAZY, mappedBy="someField")
private Set<AnotherEntities> entities;
// Constructor for JPA
// Fields aren't initalized here so that each em.load
// won't create unnecessary objects
private MyEntity() {}
// Factory method for the rest
// Have field initialization with default values here
public static MyEntity create() {
MyEntity e = new MyEntity();
e.entities = new Set<AnotherEntities>();
return e;
}
public Set<AnotherEntities> getEntities() {
return entities;
}
}
Idea no 2:
I just thought that the order of operations in EAGER and LAZY fetching may differ i.e. EAGER fetching may
Declare field entities
Fetch value for entities (I'd assume null)
Set value of entities to new Set<T>()
while LAZY may
Declare field `entities
set value of entities to new Set<T>()
Fetch value for entities (I'd assume null)'
Have to find a citation for this as well.
Idea no 1: (Not the right answer)
What if you'd annotate the getter instead of the field? This should instruct JPA to use getters and setters instead of field access.
In the Java Persistence API, an entity can have field-based or
property-based access. In field-based access, the persistence provider
accesses the state of the entity directly through its instance
variables. In property-based access, the persistence provider uses
JavaBeans-style get/set accessor methods to access the entity's
persistent properties.
From The Java Persistence API - A Simpler Programming Model for Entity Persistence