JPA OneToMany duplicate child - jpa

I am trying to implement a OneToMany relationship and having a really hard time in selecting the child records.
For example: Parent P1 has 3 Child entities and Parent P2 has 2 Child entities, say
P1 has C1,C2,C3
P2 has C4,C6
But code below returns
P1 has C1,C1,C1
P2 has C1,C1
Interestingly the number of child entities is correct, but the data itself is just duplicate of the first record. I tried setting distinct but that doesn't seem to help.
CriteriaBuilder criteriaBuilder = db2EntityManager.getCriteriaBuilder();
CriteriaQuery<Parent> searchQuery = criteriaBuilder.createQuery(Parent.class);
Root<Parent> aRoot = searchQuery.from(Parent.class);
//Constructing list of parameters
List<Predicate> predicates = new ArrayList<>();
//Adding predicates in case of parameter not being null
predicates.add(criteriaBuilder.equal(aRoot.get("a"), "A"));
predicates.add(criteriaBuilder.equal(aRoot.get("b"), "B"));
predicates.add(criteriaBuilder.equal(aRoot.get("c"), "C"));
//query itself
searchQuery.select(aRoot).where(predicates.toArray(new Predicate[]{})).distinct(true);
TypedQuery<Parent> query = db2EntityManager.createQuery(searchQuery);
parentEntities = query.getResultList();

Turns out the issue was with the Primary Key in the Child entity. The composite key was not returning unique records.

Related

Entity Framework atypical 1-[0..1] -- model-only Association -- EF LINQ select possibilities

Suppose the following tables
ParentEntities
ParentID
ChildEntities
ChildID
ParentID
These tables do not have a FK defined in the schema.
In EF designer, after generating from DB, I add an association:
- Parent Multiplicity: 1
- Child Multiplicity: 0 or 1
When I build, I get the error: "Error 3027: No mapping specified for the following EntitySet/AssociationSet - ParentChild"
But if I try to configure table mapping for the association like this..
Maps to ChildEntities
Parent
ParentID <-> ParentID (parent entity prop <-> child table column)
Child
ChildID <-> ChildID (child entity prop <-> child table column)
.. I get this: Error 3007: Problem in mapping fragments starting at lines xxx, xxx: Column(s) [ParentID] are being mapped in both fragments to different conceptual side properties.
Why this is an error doesn't make sense. Limitation of the current implementation?
[EDIT 1]
I'm able to make this work by creating a 1-N association. That's not ideal, but it works just the same, just have to add a read-only child property in a partial:
public partial class Parent
{
public Child Child { get { return Childs.Any() ? null : Childs.First(); } }
}
This seems like the best solution for me. I had to add a FK to the database to get EF to generate the association and navigation property, but once it was added I was able to remove the FK, and further updates to the model from the DB did not remove the association or Navigation properties.
[EDIT 2]
As I was investigating how to work around not caring about the association being modeled in EF, I ran into another issue. Instead of the read-only Child property I made it normal ..
public partial class Parent
{
public Child Child { get; set; }
}
.. but now I need a way to materialize that from the query:
var query = from parents in context.Parents
// pointless join given select
join child in context.Childs
on parents.ParentID equals child.ParentID
select parents;
I can select an anonymous type ..
// step 1
var query = from parents in context.Parents
join child in context.Childs
on parents.ParentID equals child.ParentID
select new { Parent = parents, Child = child };
.. but then I've got to consume more cycles getting that into my entity:
// step 2
var results = query.Select(x => {
var parent = x.Parent;
parent.Child = x.Child;
return parent; });
Is there a better/streamlined way to do this from the query select so the EF materializer can do it from the get-go? If not, then I'll resort to Edit 1 methodology ..
Ef Code first requires 1->0..1 relationships for the Child to have the same primary key.
Maybe this a similar restriction In the modeler in this circumstance.
ParentId (Key) required in Both tables.
I have never tried adding such relationships in designer afterwords in DB first.
EDIT: to match your EDIT2:
I would stay on the direction . Use Navigation properties to get from Join back to original class A and B.
query = context.Set<JoinTable>.Where(Jt=>Jt.NavA.Id == ClassAId
&& Jt.navB.Id == ClassBId)
use a select if your need entries returned from either ClassA or ClassB.

JPA OneToMany relations and performace

I have two entities: parent Customer and child Order.
Each Customer has 1,000,000 Orders for example, so it is not needed in any given time to load a Customer with all Orders but I want to have this ability to make join query on these two entities in JPA.
So because of this, I must create #OneToMany relationship for making join queries.
My question is: how to get query without making joinColumn because even in Lazy mode it is possible to load 1,000,000 objects!
I just want to get query on these object with where restrictions like native join.
If you don't want the #OneToMany relationship implicitly set in your Customer class than you don't have to. You can execute JPQL queries (in very precise manner) without the marked relationship.
Assume you have:
#Entity
public class Customer {
// all Customer-related fields WITHOUT #OneToMany relationship with Order
}
#Entity
public class Order {
#ManyToOne
private Customer owner;
}
Then if you want to get all Orders for particular Customer you can execute a simple JPQL query like that:
// Customer customer = ...
// EntityManager em = ...
String jpql = "SELECT o FROM Order o WHERE o.owner = :customer";
TypedQuery<Order> query = em.createQuery(jpql, Order.class);
query.setParameter("customer", customer);
List<Order> orders = query.getResultList();
In this way you can execute the code only when you're really sure you want to fetch Customer's orders.
I hope I've understood your problem correctly.
EclipseLink has support for QueryKeys, that allow you to define fields or relationships for querying that are not mapped. Currently there in no annotation support for query keys, but you can define them using the API and a DescriptorCustomizer.
Also you do not need the OneToMany to query on it, just use the inverse ManyToOne to query,
i.e.
Select distinct c from Customer c, Order o where o.customer = c and o.item = :item
Or,
Select distinct o.customer from Order o join o.customer c where o.customer = c and o.item = :item

Self Referencing Relationship: Selecting children and grandchildren

My ADO.Net Entity Data Model has a model called ABC below (modeled after a self-referencing table).
ABC Properties are
----------
ParentID
Child ID
ABC Navigation Properties are
----------
ParentCategory (refers to the parent category or the 0..1 side of the relationship)
SubCategories (refers to the children or the * side of the relationship, represents the navigation property for the children)
I want to select the children and grandchildren for a specific ParentID (i.e. not the top of the hierarchy ). How can I accomplish this. Can someone please propose an example. Thanks
I have tried the solution proposed below in vb, but it is only loading one level;
I am doing this in VB so apologies to C# programmers.
Protected Sub Button2_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button2.Click
Dim ctx = New links2Entities
Dim query = From c In ctx.PBS.Include("SubCategory.SubCategory") Where (c.Parent_ID = 7)
For Each result As PB In query
Debug.WriteLine("ID: {0}", result.Child_ID)
Next
End Sub
If you need to select entity by its Id and eager load two levels of its children you need to do:
var query = context.ABC.Include("SubCategories.SubCategories")
.Where(e => e.Id == id);
In case of EF 4.1 it should be:
var query = context.ABS.Include(e => e.SubCategories.Select(s => s.SubCategories))
.Where(e => e.Id == id);
If you need to eager load all sub categories in any depth there is not way to tell it EF.

JPA criteriabuilder "IN" predicate on foreign key error: Object comparisons can only use the equal() or notEqual() operators

I want to select a list of file references from a table by looking at which users have the rights to retrieve that file. To do this I have 3 tables, a file table, an access control table, and a users table.
I am using JPA and Criteriabuilder (because there are more tables involved and I need dynamicle create the query, I am leaving out the other tables and predicates from this question for the sake of readability).
The following code works
CriteriaBuilder queryBuilder = em.getCriteriaBuilder();
CriteriaQuery<File> queryDefinition = queryBuilder.createQuery(File.class);
Root<File> FileRoot = queryDefinition.from(File.class);
List<Predicate> predicateList = new ArrayList<Predicate>();
Predicate userPredicate = FileRoot .join("FileAccesControlCollection").join("userId").get("usersId").in(loggedInUser.getUsersId());
predicateList.add(userPredicate );
queryDefinition.where(predicateArray).distinct(true);
Query q = em.createQuery(queryDefinition);
List<Files> results = (List<Files>) q.getResultList();
For the userpredicate I want to leave out the last join to the users table because the ID that I want to filter on is already present in the FileAccesControlCollection table, and a join is a computational expensive database operation.
What I tried is to do this:
Predicate userPredicate = FileRoot .join("FileAccesControlCollection").get("usersId").in(loggedInUser.getUsersId());
But I guess because the userId value in the FileAccesControlCollection entity class is a foreignkey reference to the Users class I get the following error:
Exception Description: Object comparisons can only use the equal() or notEqual() operators. Other comparisons must be done through query keys or direct attribute level comparisons.
Is there a way, using the loggedInUser entity or its Id, to filter the files by just joining the File class to the FileAccesControlCollection class and filtering on the userId foreign key? I am kind of new to JPA and using google lead me to a lot of pages but not a clear answer for something which seems to me should be possible.
So "userId" is mapped as a OneToOne? Then you could do,
get("userId").get("id").in(...)
You could also add a QueryKey in EclipseLink using a DescriptorCustomizer for the foreign key field and then use it in the query,
get("userFk").in(...)
try this:
Predicate userPredicate = FileRoot.join(FileAccesControlCollection.class).join(Users.class).get("{id field name in class Users}").in(loggedInUser.getUsersId());
good luck.

Entity Framework-How To Add To Entites With Navigational Properties

I would like to add a record to a SQL Server table using the Entity Framework. My table's entity has foreign keys and so has navigational properties for those fields. When adding a new record/entity, how do I populate the foreign key fields since they don't appear as properties of the entity?
The easiest way is to do a query for the related entities and use the Navigation Properties:
i.e.
Product p = new Product{
ID = 5,
Name = "Bovril",
Category = ctx.Categories.First( c => c.ID == 5)
};
ctx.AddToProducts(p);
ctx.SaveChanges();
If you want to avoid the database query the easiest approach is probably to use a STUB entity i.e.
// this is a stub, a placeholder for the real entity
Category c = new Category {ID = 5};
// attach the stub to the context, similar to do a query
// but without talking to the DB
ctx.AttachTo("Categories", c);
Product p = new Product{
ID = 5,
Name = "Bovril",
Category = c
};
ctx.AddToProducts(p);
ctx.SaveChanges();
If you want more help on this stub technique check out this blog post on the topic.