problem with navigation properties in entity framework - c#

When I execute this query I can navigate in TypeP property:
var items = from item in context.ProductosBodegas.Include("Product.TypeP")
select item;
But when I execute this query the TypeP Property is null:
var items = from item in context.ProductosBodegas.Include("Product.TypeP")
select item.Product;
Why is this?

Looks like Include only affects the directly returned object :
http://msdn.microsoft.com/en-us/library/bb896272.aspx
Otherwise you can call
item.TypePReference.Load()
But this can (and will) lead to perfornance issues (N+1 select), if used in a loop.
Another option would be to "reverse" your query, assuming relationship between Product and ProductosBodegas is bidirectional :
var items = context.Products
.Include("TypeP")
.Where(p => p.ProductosBodegas.Any( /* include condition here if needed */ ))

As far as I know Entity Framework ignores Includes as soon as you don't want to return full entities but only projections. See for instance the answer here. I am not sure if that is still valid for all types of projections but apparently it is still valid in your situation.
You can workaround this by adding the navigation property you want to have loaded into an anonymous type:
var items = from item in context.ProductosBodegas
select new {
Product = item.Product,
TypeP = item.Product.TypeP
};
(You don't need .Include here anymore.) After executing this query (by using .ToList() for instance) you can project to only the part of the anonymous type you want to have, like so:
var products = items.ToList().Select(x => x.Product);
The elements in this products collection have loaded the TypeP reference property now.
Edit:
Important note: Don't change the order of .ToList and .Select.... While this ...
var products = items.Select(x => x.Product).ToList();
... is also syntactically correct and also returns an enumeration of products, the TypeP reference will NOT be loaded in this case. The query for the anonymous type must be executed at first in the database and the anoynmous type collection loaded into memory. Then you can throw away the part of the anoynmous type you don't want to have by the .Select method.

you should load product first
var items = from item in context.ProductosBodegas.Include("Product").Include("Product.TypeP")
select item;

Related

C# Join two tables using Include. Data comes from a Model

I am very new with C# and need some help. I am working on someone elses code and they are pulling data from a Model. I am trying to join two tables and need to use Include but the error is '==' cannot be applied to Guid and IQueryable. Could someone help with this please. Thanks in advance!
Yes, I am.
.Where() represents your filter. .Select() represents what you want back. If you just want the entities back you don't need a .Select().
If you have an association between menu items and MenuItemProgramData, for example, a MenuItem holds a reference to a MenuItemProgramData then you don't even need the first ID select statement:
return context.DbMenuItems
.Where(x => x.MenItemsProgramData.Plu == plu);
Note: If your context defines DbSet<T> for your various top level entities, you can just use context.Ts rather than .GetItems<T>.
If the relationship exists then this is the preferred approach. Let SQL do the work. The consumer of your method can further .Select() the applicable data, sort it, paginate it, and even append .Include() if you do want to interact with the entire entity graph.
If you don't have a relationship between the menu item and that program data, and know that the # of item IDs from the first query will remain relatively small (say, sub-100) then:
var itemIds = context.DbMenuItemProgramDatas
.Where(x => x.Plu == plu)
.Select(x => x.MenuItemId)
.ToList();
Without the .ToList() you are dealing with an IQueryable which EF would potentially still attempt to translate to SQL statements when later consumed. By using .ToList() it will execute the SQL and populate a List<int>. (Assuming the menu item ID is an int)
To get the IQueryable menu item data rows:
return context.DbMenuItems
.Where(x => itemIds.Contains(x.Id));
And that is it.
Edit: Based on the comment "I want to return a field named ParentId to know if it is empty or not. That's all but I need both tables linked to get that answer."
Additionally, looking back at the original code, the naming of the method is a bit misleading. GetItemProgramDataForSubItems implies returning MenuItemsProgramData rather than MenuItems... However, if ParentId is a property of MenuItem, then the caller of this method can use:
var hasParentId = context.GetItemProgramDataForSubItems(plu)
.Any(x => x.ParentId.HasValue);
If the ParentId is on the MenuItemsProgramData:
var hasParentId = context.GetItemProgramDataForSubItems(plu)
.Any(x => x.MenuItemsProgramData.ParentId.HasValue);
Beyond that, you may want to elaborate on what your entities and relationships look like, and what exactly you aim to accomplish from your method or business logic.

IQueryable<T>.Include() gets ignored

I have Parent and Child entities related to each other as 1 to M. I need to query childs together with parents within a single SQL query, but the Include method is not properly working for some cases.
This one makes a correct single query for both Parent and Child tables (via JOIN):
var r1 =
ctx.Set<Parent>()
.Include(p => p.Childs)
.Where(p => p.Id == 1)
.ToList();
Once i create an anonymous object on the fly, children are getting lost and SQL contains only Parent's fields. Retrieval of children remains lazy - they are still not loaded:
var r2 =
ctx.Set<Parent>()
.Include(p => p.Childs)
.Where(p => p.Id == 2)
.Select(p => new { myParent = p})
.ToList();
Questions:
Why it's so?
How can I construct a new anonymous object in my LINQ so childs are not geting lost?
p.s. i'd like keep Childs property of Parent virtual.
This is a general problem in all versions of EF known to me. EF tries hard to pass the 'includes' as far as possible, but when "the shape of the query changes", the 'includes' are irreversibly lost.
The "shape" of the query changes for example, when:
a projection is used (select not whole object but just some fields, or different object)
a group-by or other aggregation is used
.. and probably in some more cases, which currently I dont remember.
Sadly, I also dont remember where on MSDN I stumbled upon the "shape of the query" explanation. If I find it, I'll drop here a link.
The solution is actually quite simple: simply specify the 'include' part not early, but at the final result. So, instead of set.include(x) at beginning, do .Select( .. => new { .., x }) to include the 'x' manually. It also works during grouping, as you can do a projection there too.
However, this is not a solution. This is a manual patch/hotfix, which does not solve anything. Considering that you might want to expose a "IQueryable<>" through some interface, you may like to expose a "base query" with some things already .Included. And of course, this is simply not possible to do in a general way, as if the client of the interface does a projection or grouping, he will lose the includes and he will not even know which ones should be. For me, this is a major deficiency in EF.
EDIT: just found one: .Include in following query does not include really Not MSDN, but just as good.
As you're creating an anonymous object the Parent DbSet Set<Parent>() of the context is not being populated with any data and therefore neither are the Children being stored in the context. One solution could be to add the children to the anonymous object but I'm not sure this would cause them to be added to the Set<Child> DbSet.
var r2 = ctx.Set<Parent>()
.Include(p => p.Childs)
.Where(p => p.Id == 2)
.Select(p => new { myParent = p, children = p.Childs })
.ToList();

Entity Framework Many to Many Filter

I have a many to many relationship in EF Code First between Contacts and Lists. ProxyCreation and LazyLoading are disabled to allow serialization of the entities.
I have a query that is meant to return contacts that are in a given list.
// GET api/Contacts
[Queryable]
public IQueryable<Contact> GetContacts(int bulkListId)
{
var bulkList = db.BulkLists.Include(c => c.Contacts).Where(c => c.ID == bulkListId).SingleOrDefault();
if (bulkList == null)
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
return bulkList.Contacts.AsQueryable().OrderBy(c => c.ID).Include(c => c.AddressBookType).Include(c => c.BulkLists);
}
Although this works, it doesn't work as intended. It results in the correct set of contacts who are in a given list but these contacts only have that list populated in their Lists property of the relationship. So when this is serialized and gets back to the client it hides the other lists that the contacts are members of.
I can't see how the query is filtering it in this way and how I might change it to include the full set of lists. Any advice would be very much appreciated.
You're cheating! :)
By adding AsQueryable() to bulkList.Contacts you make it possible to continue with Include without making the compiler complain. BUT...
As per MSDN on DbExtensions.Include:
This extension method calls the Include(String) method of the IQueryable source object, if such a method exists. If the source IQueryable does not have a matching method, then this method does nothing.
(emphasis mine)
And EntityCollection does not have an Include method, so nothing happens.
You'll have to expand the include list in your first statement, probably like so:
db.BulkLists
.Include(c => c.Contacts.Select(c => c.AddressBookType))
.Include(c => c.Contacts.Select(c => c.BulkLists))

LINQ get collection in anonymous type

i have the following LINQ statement:
var query =(from item in _itemRepository.FindAll()
where item.Id == "20649458"
from singelitem in item.ListOfChildren
where singelitem.Property == "singelitem"
from manyitems in item.ListOfChildren
where manyitems.Property == "many"
select new
{
item.Id,
singelitem,
manyitems
});
var result = query.ToList();
Tasks is a collection of objects and the where clause tasks.Property == "something" matches several items in the collection, but when i use a anonymous type in the select, i only get back one item (the first) of the matching results instead of a collection of Tasks. How can i get back all the matching tasks in a collection?
Edit:
What really happends is that i get flat objects, (just like a db result set from a join statement).
When you don't use anonymous type you're dealing with entity class which lazy loads the tasks when you access them. If you want to load tasks with your results try using Include method to eager load children. See How do you construct a LINQ to Entities query to load child objects directly, instead of calling a Reference property or Load()
This is the proper behavior of Linq. In fact what you are expecting is not possible. You are expecting a single item matching item.Id == "123"; and what if more than one? it just creates an anonymous item for each matched item. Just think of changing the first "from" statement with the second one; what would you expect?
Also, there is no relationship between first "from" statement and the second one which makes this query a bit "strange". Why not just splitting the query into 2; and creating a new object with the desired properties?

Entity Framework: Why do navigation properties disappear after a group by?

I retrieve a collection with the following query:
var numbers = _betDetailItem.GetBetDetailItems().Where(betDetailItem => betDetailItem.BetDetail.Bet.DateDrawing == resultToCreate.Date && betDetailItem.BetDetail.Bet.Status == 1).Where(condition);
Right there I'm able to access my navigation properties and navigate through binded info. Note how I actually use them to filter the data.
After I group the results, the navigation properties become null.
var grouped = numbers.GroupBy(p => p.BetDetail.Bet);
//Iterate through the collection created by the Grouping
foreach (IGrouping<Bet, BetDetailItem> group in grouped)
{
var details = group.Key.BetDetails; //This is what doesn't work. BetDetails is a navigation property which was accessible in the previous query.
}
Am I doing something wrong?
You are confusing LINQ to Entities and object operations.
This is LINQ to Entities:
var numbers = _betDetailItem.GetBetDetailItems().Where(betDetailItem => betDetailItem.BetDetail.Bet.DateDrawing == resultToCreate.Date && betDetailItem.BetDetail.Bet.Status == 1).Where(condition);
So is this:
var grouped = numbers.GroupBy(p => p.BetDetail.Bet);
These are object operations:
foreach (IGrouping<Bet, BetDetailItem> group in grouped)
{
var details = group.Key.BetDetails; //This is what doesn't work. BetDetails is a navigation property which was accessible in the previous query.
}
In LINQ to Entities, there is never any need to think about loading related instances. You can always refer to any property of any object. However, at some point, you want to move out of the LINQ to Entities world and into object space, because you want to work with instances of type BetDetail instead of type IQueryable<BetDetail>. This means that the Entity Framework is now required to generate SQL to retrieve data from the database. At that point, it doesn't snow which related instances you will be accessing in your code later on. Nothing in your LINQ to Entities query forces the loading of the related Bet. So unless you do something to cause it to be loaded, like use eager loading, explicit loading, or EF 4 lazy loading, it won't be loaded.
Using lazy loading (e.g., in Entity Framework 4, or in another ORM) will make this code appear to function, but it will be unnecessarily slow, due to the large number of database queries generated. A better solution would be to use eager loading or projection. This way there will be only one DB roundtrip.
Once you do a GroupBy(), you're no longer dealing with your entities -- they have been... well, grouped, so the var in var grouped = ... is now of type IEnumerable<IGrouping<.... As such, the methods available on the items in the grouped collection are the methods of the IGrouping<> interface.
You may want to OrderBy() instead of GroupBy(), depending on your need, or you'll need to iterate on two levels: iterate over each group in grouped, and over each member within each of those.
Once you are inside of a particular IGrouping<>, you should have access to the properties for which you are looking.

Categories