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

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;

Related

Where Query In One-One RelationShip in EF Repository Pattern

Following is my database architecture, three entities:
Load
ID_Load
From
To
Bids[]
Bid
ID_Bid
ID_Load
Amount
Load
Order
Order
ID_Order
Status
Amount
Bid
Load
Load and Bid : One to Many -- Load can receive multiple Bids
Order and Bid : One to One -- A single bid will be mapped with a order
Order and Load : One to One -- An order can have only one Bid
As you can see above I don't have ID_Load or ID_Bid properties in the order Entity as EF generate these automatically in the database, so the properties for these two fields are not added in the Order Entity
I am currenlty using Repository pattern with Code First in my project.
Now I want to get the Order information by ID_Load/ID_Bid (as there is a one to one relationship of Bid-Order and Load-Order table)
I don't want to run any SP or Select query in the application, but having issue while doing this.
If I run SQL I will have to write following query:
Select * from Order Where ID_Load = 123
Or
Select * from Order Where ID_Bid = 123
What is the alternative of this in EF/Repository Patterns in such situations.
Can anyone please help me with this.
Thanks,
Get order by Bid ID:
long bidId; // Id of Bid
var order = dbContext.Orders.Single(o => o.Bid.ID_Bid == bidId);
Get order by Load ID:
long loadId; // Id of Load
var order = dbContext.Orders.Single(o => o.Load.ID_Load == loadId);
If Bid and Load are optional for Order, use SingleOrDefault instead of Single. Single will throw an exception if the queried item does not exist, SingleOrDefault will return null.
Alternatively, if you need to load the Bid using its ID anyway:
var bid = dbContext.Bids.Find(bidId);
var order = bid.Order;
This can be optimized by forcing eager loading:
var bid = dbContext.Bids.Include(b => b.Order).SingleOrDefault(b => b.ID_Bid == bidId);
var order = bid.Order;

LINQ to Entities does not recognize the method with Let Statement

I am in the process of converting an application that uses LINQ to SQL over to LINQ to Entities. I use a repository pattern and I have run in a problem that works in LINQ to SQL but not Entities.
In my data layer, I use LINQ statements to fill my object graph so that none of my database entities are exposed anywhere else. In this example, I have a Lookup Respository that returns a list of Categories. It looks like this:
public IQueryable<Entities.DomainModels.Category> getCategories()
{
return (from c in Categories
where !c.inactive
orderby c.categoryName
select new Entities.DomainModels.Category
{
id = c.categoryID,
category = c.categoryName,
inactive = c.inactive
});
}
Later, I want to put the categories into a sub query and it looks like this:
var d = from p in Programs
let categories = (from pc in p.Categories
join c in getCategories() on pc.categoryID equals c.id
select c)
select new
{
id = p.id,
title = p.title
categories = categories.ToList()
};
When I run this, I get the following error:
LINQ to Entities does not recognize the method 'System.Linq.IQueryable`1[Entities.DomainModels.Category] getCategories()' method, and this method cannot be translated into a store expression.
For reference, the following works though it doesn't return the data I need (it's basically a join):
var q = from p in Programs
from pc in p.Categories
join c in getCategories() on pc.categoryID equals c.id
select new
{
id = p.id,
category = c
};
I understand what the error means in concept however LINQ to SQL would make it work. I have this pattern throughout my data layer and I really want to keep it. Should this be working? If not, how can I modify it without mixing my layers.
You cant pass getCategories() to EF.
The query must be destructible to expression tree.
Calculate getCategories() first.
eg
var simpleList = getCategories().Select(id).Tolist;
then use a contains
where(t=> simpleList.Contains(t.CatId) // or the query syntax equivalent

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.

Many-to-Many Inserts with Entity Framework

Say I have two entities with about 20 properties per entity and a Many-to-Many relationship like so:
User (Id int,Name string, .......)
Issue (Id int,Name string, .......)
IssueAssignment (UserId,RoleId)
I want to create a new Issue and assign it to a number of existing Users. If I have code like so:
foreach(var userId in existingUserIds)
{
int id = userId
var user = _db.Users.First(r => r.Id == id);
issue.AssignedUsers.add(user);
}
_db.Users.AddObject(user);
_db.SaveChanges();
I noticed it seems terrribly inefficient when I run it against my SQL Database. If I look at
the SQL Profiler it's doing the following:
SELECT TOP(1) * FROM User WHERE UserId = userId
SELECT * FROM IssueAssignment ON User.Id = userId
INSERT INTO User ....
INSERT INTO IssueAssignment
My questions are:
(a) why do (1) and (2) have to happen at all?
(b) Both (1) and (2) bring back all fields do I need to do a object projection to limit the
fields, seems like unnecessary work too.
Thanks for the help
I have some possible clues for you:
This is how EF behaves. _db.Users is actaully a query and calling First on the query means executing the query in database.
I guess you are using EFv4 with T4 template and lazy loading is turned on. T4 templates create 'clever' objects which are able to fixup their navigation properties so once you add a User to an Issue it internally triggers fixup and tries to add the Issue to the User as well. This in turns triggers lazy loading of all issues related to the user.
So the trick is using dummy objects instead of real user. You know the id and you only want to create realtion between new issue and existing user. Try this (works with EFv4+ and POCOs):
foreach(var userId in existingUserIds)
{
var user = new User { Id = userId };
var _db.Users.Attach(user); // User with this Id mustn't be already loaded
issue.AssignedUsers.Add(user);
}
context.Issues.AddObject(issue);
context.SaveChanges();