I have a problem trying to load a tree, this is my case, I have an entity associated with itself (Hierarchic) with n levels; the question is, Can I load eagerly the entire tree using ICriteria or HQL?
Thanks in advance for any help.
Ariel
Yes... just set correct fetchmode.
i'll include example in a minute.
Example taken from here =>
IList cats = sess.CreateCriteria(typeof(Cat))
.Add( Expression.Like("Name", "Fritz%") )
.SetFetchMode("Mate", FetchMode.Eager)
.SetFetchMode("Kittens", FetchMode.Eager)
.List();
You can specify to eager load child of child too =>
.SetFetchMode("Kittens.BornOn", FetchMode.Eager)
In case you are using Linq to NHibernate, use Expand method =>
var feedItemQuery = from ad in session.Linq<FeedItem>().Expand("Ads")
where ad.Id == Id
select ad;
And i would recommend to use helper method that creates string from passed in lambda expression.
Quite likely that it's possible to tell Criteria to load whole tree. But i'm not aware about that and i prefer specifying what exactly i need (seems dangerous to load everything).
Does this helps?
Related
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.
Could Someone help me to clarify the difference between :
var query = awlt.People.Include(p => p.EmailAddresses)
.Where(p => p.LastName.Equals(lastName))
.SelectMany(a => a.EmailAddresses)
.Select(a => a.EmailAddress1);
var query = awlt.People
.Where(p => p.LastName.Equals(lastName))
.SelectMany(a => a.EmailAddresses)
.Select(a => a.EmailAddress1);
I get the same results in both cases without knowing the difference .
Does the Eager Loading require using Include ?
The both query are retrieving the related data just first query by using Eager Loading (and yes Eager loading is achieved by use of the Include method as you guessed) and the second query by using Lazy loading which is by default. But since your query will only returns EmailAddresses because of the Select() and SelectMany() operations the Include() method doesn't change the behavior. To see when Include() method is matter in your example read the following lines that I will prove it in one example:
To know some difference between this two kind of loading related entities Eager loading is typically more efficient when you need the related data for all retrieved rows of the primary table. And also when relations are not too much, eager loading will be good practice to reduce further queries on server. But when you know that you will not need a property instantly then lazy loading maybe a good choice. And also eager loading is a good choice in a situation where your db context would be disposed and lazy loading could not take place anymore.
To prove that one is Lazy Loading and one is Eager Loading consider the following code:
public List<Person> GetEmailAddresses()
{
using (yourEntities awlt = new yourEntities())
{
var query = awlt.People
.Where(p => p.LastName.Equals(lastName));
return query.ToList();
}
}
After calling this method, You cannot load the related entity lazily because the db is disposed. To prove try this:
var query = GetEmailAddresses();
foreach (var item in query.SelectMany(a => a.EmailAddresses).Select(a => a.EmailAddress1))
{
MessageBox.Show(item);
}
And you will get this error:
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
But if you change the GetEmailAddresses to use Eager Loading like this:
public List<Person> GetEmailAddresses()
{
using (yourEntities awlt = new yourEntities())
{
var query = awlt.People.Include("EmailAddresses")
.Where(p => p.LastName.Equals(lastName));
return query.ToList();
}
}
Then the below code should works fine:
var query = GetEmailAddresses();
foreach (var item in query.SelectMany(a => a.EmailAddresses).Select(a => a.EmailAddress1))
{
MessageBox.Show(item);
}
So in a situation where your db context would be disposed the Eager Loading would be a better choice.
Don't know about EF 7, but in EF 6 both those statements produce the same queries to database and so are essentially the same. There is no lazy loading, no eager loading (in a sense this term is usually used) whatsoever.
You need to Include only properties of entities you materialize. In the example above you materialize Person.EmailAddresses.EmailAddress1, but you include just Person.EmailAddresses - this has no effect (for more details see for example here).
Consider this sample code (details does not matter, there is just Error entity with Code navigation property):
// note we materialized query
var errors = ctx.Errors.Include(c => c.Code).ToArray();
// no lazy loading happens here - we already loaded all related Codes with Include
var codeIds = errors.Select(c => c.Code.CodeID).ToArray();
And this one:
// no need to include here!
var codeIds = ctx.Errors.Select(c =>c.Code.CodeID).ToArray();
And with include:
// include has no effect here!
var codeIds = ctx.Errors.Inlcude(c => c.Code).Select(c => c.Code.CodeID).ToArray();
What is eager loading? It's when you include additional data to the related entity using Include statement. Here Include statement has no effect, it's just does nothing, so we cannot name that eager loading.
What is lazy loading? It's when navigation property is loading when you access it for the first time. You do not do this in your examples, so there is no lazy loading either.
Both examples just execute identical queries to database (after you materialize them with enumeration`ToArray` etc).
The result of the two queries is exactly the same (also about 'eager' and 'lazy' load).
In this case I think that also the query are very similar or the same BUT never trust EF Provider generated queries. To see the generated queries you can stop the program with a breakpoint and have a look to query object (pointing the mouse on it). That is the query generated by EF Provider.
About Eager loading (the Include statement) in this case it should not be useful because is used to load properties of the output object. In this case you are selecting EMailAddress1 so with Include you could eager load properties of EMailAddress1 (and avoid lazy queries during EMailAddress1 access).
You can find the difference if you look into SQL Server Profiler after the query is run. So in your first case there is only one query going to your database and fetching records from People table as well as EmailAddresses table whereas in the second case it does two queries to database and fetches People first and then EmailAddresses in a second query. Thus the first scenario is called eager loading and the second one lazy loading.
I have an issue trying to maximize the performance of our listview that has pages.
I want the entity framework to do a select statement, but only return a range of the result (range = the items of one page of the listview).
I have searched google but didn't find any results on this. I only found that I can do a .ToList().GetRange(start index, end index), but then all items would be loaded in memory, and that is what I would like to avoid...
Can someone tell me if this can be done? (I don't want to use a stored procedure or view or something like that because our listview has to be reusable...)
Thanks!
You should be able to use .Take(x).ToList()
edit: sorry, try .Skip(startPosition).Take(numberOfItems).ToList()
And if you are not using lazy loading be sure to use Query() before Load() when applying filters to avoid loading the whole collection before applying filters :
context.Entry(blog)
.Collection(b => b.Posts)
.Query()
.Skip(startPosition)
.Take(numberOfItems)
.Load()
.ToList();
When using the Query method it is usually best to turn off lazy loading for the navigation property. This is because otherwise the entire collection may get loaded automatically by the lazy loading
mechanism either before or after the filtered query has been executed.
For more details : http://msdn.microsoft.com/en-us/data/jj574232.aspx
I am creating a sort of family tree in entity framework 4.0. I have come across an issue where the Entity Framework is only loading the immediate children. It does not load the children of the children even though i have an include specified.
For example, this is my query :-
public IQueryable<TreeMember> GetTreeMembers(int userId)
{
return this.ObjectContext.TreeMembers.Include("RelatedTreeMembers").Where(u => u.UserId == userId && u.RelatedTreeMemberId == null);
}
This would load the 1st level of children. But it does not load the children of the children. If i have to include children of the children, i have to write :-
public IQueryable<TreeMember> GetTreeMembers(int userId)
{
return this.ObjectContext.TreeMembers.Include("RelatedTreeMembers.RelatedTreeMembers").Where(u => u.UserId == userId && u.RelatedTreeMemberId == null);
}
This is quickly getting to be frustrating because i don't know how many times should i have to write this RelatedTreeMembers as a family tree can extend upto N level. How do i get past this issue? If my question is not clear please let me know.
Thanks in advance :)
That is how EF works. You want to define recursive (hierarchical) query which is not possible with eager loading in EF. You always have specify exactly which navigation properties you want to load - obviously in this scenario you can't because you don't know how deep is your recursion.
I like the idea #Magnus suggested with CTE but I would not use DB View. I would use stored procedure. The reason is that you already have entity TreeMember mapped to a table. If you define the view you will not be able to map it to the same entity type. You will need new entity for the view. If you use stored procedure you can map its result to already existing entity type.
Another way is to use lazy loading.
Write a view with a recursive CTE and than use that with Linq.
http://msdn.microsoft.com/en-us/library/ms186243.aspx
I have my NHibernate mappings set to lazy loading = true.
In my CustomersViewModel I have something like:
foreach (Customer c in _customerRepository)
{
this.Customers.Add(new SingleCustomerViewModel(c));
}
This obviously kills all the lazy loading, since the customers are passed one by one.
How do I get my collections (including subcollections and sub-subcollections a.s.f.) of model-objects into the corresponding ObservableCollections of my ViewModels to bind to the UI?
This seems to be a common problem, but I found no answer, neither here nor on the Googles ...
I am not sure I completely understand the question .
But I was thinking why not change your getCustomers method to
IEnumerable<SingleCustomerViewModel> getCustomers(){
return from c in _customerRepository select SingleCustomerViewModel(c);
}
Since LINQ expressions are lazily evaluated you nhibernate collection wont be initialized until its actually bound to the UI .
This is a classic "SELECT N+1" problem: whichever query layer you are using for NHibernate offers you a way to eagerly load the child collections in your initial query to avoid this row-by-row query pattern.
With the LINQ provider, for example:
session.Query<Customer> ()
.FetchMany (c => c.Widgets) // eagerly load child collections
.ThenFetchMany (w => w.Frobbers); // now get grandchild collection
If you're using HQL, just add the fetch keyword to your joins.