OrderBy Expression When Using An Association Table - entity-framework

I have two tables: CommentCategories and Comments. It is a many-to-many relationship. There is a CommentCategory_Comment association table. But that table contains a orderOfCommentInCategory field, so EF represents the association by creating a seperate entity rather than navigation properties.
I am trying to get the comments under a certain category and orer them by the orderOfCommentInCategory field. How should be the OrderBy expression that needs to be added to the query below?
List<Comment> comments = category.CommentCategory_Comment
.Select(ccc=>ccc.Comment)
.OrderBy(???)
.ToList();

As #GertArnold recommends the only you need to do is order first before select:
var comments = category.CommentCategory_Comment
.OrderBy(c=>c.orderOfCommentInCategory )
.Select(ccc=>ccc.Comment)
.ToList();
Using query syntax:
var query= from cc in category.CommentCategory_Comment
orderby cc.orderOfCommentInCategory
select cc.Comment;
var comments=query.ToList();

Related

Entity Framework: selecting from multiple tables

I have a statement:
var items = from e in db.Elements
join a in db.LookUp
on e.ID equals a.ElementID
where e.Something == something
select new Element
{
ID = e.ID,
LookUpID = a.ID
// some other data get populated here as well
};
As you can see, all I need is a collection of Element objects with data from both tables - Elements and LookUp. This works fine. But then I need to know the number of elements selected:
int count = items.Count();
... this call throws System.NotSupportedException:
"The entity or complex type 'Database.Element' cannot be constructed in a LINQ to Entities query."
How am I supposed to select values from multiple tables into one object in Entity Framework? Thanks for any help!
You are not allowed to create an Entity class in your projection, you have to either project to a new class or an anonymous type
select new
{
ID = e.ID,
LookUpID = a.ID
// some other data get populated here as well
};
Your code doesn't work at all. The part you think worked has never been executed. The first time you executed it was when you called Count.
As exception says you cannot construct mapped entity in projection. Projection can be made only to anonymous or non mapped types. Also it is not clear why you even need this. If your class is correctly mapped you should simply call:
var items = from e in db.Elements
where e.Something == something
select e;
If LookupID is mapped property of your Element class it will be filled. If it is not mapped property you will not be able to load it with single query to Element.

Fetch only key value from EF association

I've set up a many-to-many association between two tables based on a third table that just holds a pair of key values. Now I'd like to do a query that groups the right tables key values by the lefts without needing other data.
LeftTable { LeftID, LeftField1, LeftField2 }
JoinTable { LeftID, RightID}
RightTable { RightID, RightField1, RightField2 }
Is there any way to essentially just query the JoinTable and get all the 'RightIDs' grouped by the 'LeftIDs' without the SQL trying to fetch the fields from either side?
The JoinTable is not an entity in its own right in the model, but is mapped to the association.
I've experimented a bit with both using ObjectQuery and EntityCommand (ESQL) and both seem to still load in the other fields by joining to RightTable which I don't need.
My ESQL looks something like:
SELECT lt.LeftID, (SELECT rt.RightID
FROM NAVIGATE(lt, MyModel.LeftToRightAssoc, RightTable) as rt)
FROM MyEntities.LeftTable as lt;
but the generated SQL is still fetching in RightField1 and RightField2.
Surely there must be a simpler way to do this?
Assuming that your class Left has a navigation property Rights (a collection of Right entities) you could try this:
var list = context.Lefts.Select(l => new
{
LeftId = l.LeftId,
RightIds = l.Rights.Select(r => r.RightId)
});
foreach (var item in list)
{
Console.WriteLine("LeftId = {0}", item.LeftId);
foreach (var rightId in item.RightIds)
{
Console.WriteLine("RightId = {0}", rightId);
}
}
You would get a collection of anonymous type objects where each element has the LeftId and a collection of corresponding RightIds. This query should not touch the other fields like RightField1, etc. Instead of an anonymous type you could also create your own custom type and then project into this type in the query above.

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 limit length of a returned nvarchar column

I want to limit the length of a column in an EF query, ala:
var query = from ce in entities.ContactEvents
.Include("Person")
.Include("Orders")
where ce.PersonID = personID
orderby ce.DateTimeContact descending
select new ContactEvent
{
ID = ce.ID,
DateTimeContact = ce.DateTimeContact,
Description = ce.Description.Substring(0, 500),
Orders = ce.Orders
};
The query fails because the EF can't project the complex type Orders.
The entity or complex type 'Model.ContactEvent' cannot be constructed in a LINQ to Entities query.
I've tried a few different ways to do the same thing such as use an explicit join in the LINQ expression but so far I always hit a snag populating the Orders collection in the select projection.
Any ideas on how I can construct my query? Ideally I don't even want to use a select projection but I'm assuming I need to in order to be able to limit the length of the description column returned from the database.
You cannot project to entity types. That is the limitation. If you want to return projection (calling select new) you must either return anonymous type or custom non entity type. If you want to return entity type you must always return whole column from linq-to-entities. You can try to trim the column after object is materialized by using:
var data = (from ce in entities.ContactEvents
.Include("Person")
.Include("Orders")
where ce.PersonID = personID
orderby ce.DateTimeContact descending
select ce)
.AsEnumerable()
.Select(e => new ContactEvent
{
ID = e.ID,
DateTimeContact = e.DateTimeContact,
Description = e.Description.Substring(0, 500),
Orders = e.Orders
});

Entity Framework: Find EntityKey Values for One-to-Many

In EF, it is possible to write the following line:
orderLine.OrderReference.EntityKey.EntityKeyValues[0].Value
Which results in the ID of the associated OrderReference.
What would be the solution if I wanted to know the ID's of the orderLines associated with an order?
The point of the line you show is to get the ID without loading orderLine.Order. But you can't get the IDs of a collection without loading. So just look at the ID property, either directly or from the context.
// from context
var lineIds = (from o in Context.Orders
where o.Id = someId
from l in o.Lines
select l.Id).AsEnumerable();
// from loaded order
if (!order.Lines.IsLoaded) order.Lines.Load();
var lineIds = from l in order.Lines
select l.Id;