Load a single related object - c#

I need to load a single related object from an navigation property (ICollection) to send to my MVC View.
This can save me from unnecessary db access and load.
I've found this article about loading related objects but didn't figure out how to load one single related object from the list.
To be short, I need the object and inside its navigation property one single related object.
How to achive this?

You can't do this using Include. Include will bring back all related entities for the navigation property. You can either write two separate queries or write a join in your query.
Writing two queries:
var princess = context.Princesses.Find(id);
var unicorns = context.Unicorns.Where(u => u.PrincessId == id && u.UnicornName == "Blinky");
princess.Unicorns = unicorns.ToList();

Related

Does EF automatically load many to many references collections

Imagine we have the following db structure
Organization
{
Guid OrganizationId
//....
}
User
{
Guid UserId
}
OrganizationUsers
{
Guid OrganizationId
Guid UserId
}
When the edmx generated this class it abstracts away the OrganizationUsers into a many to many references. So no POCO class will be generated for it.
Say I'm loading data from my context, but to avoid Cartesian Production, I don't use an include I make two seperate queries.
using(var context = new EntitiesContext())
{
var organizationsQuery = context.Where(FilterByParent);
var organizations = organizationsQuery.ToList();
var users = organizationsQuery.SelectMany(x => x.Users).Load();
}
Is it safe to assume that the connected entitites are loaded?
Would this make any difference if I loaded the users directly from the DBSet?
From database point of view:
Is it safe to assume that the connected entitites are loaded?
Yes It's safe, because first organizations being tracked by EF Change Tracker and then by calling Load in next statement EF knows that results should be attach to tracked entities
Would this make any difference if I loaded the users directly from the DBSet?
In fact using Load this way does nothing better than Include!
If you use Include EF translate it to LEFT JOIN, if you use Load it will be translated to INNER JOIN, and if you fetch Users directly by their ids using Contains method it will be translated to IN on Sql side.
In Load and Contains cases you execute two query (in two pass) on Sql, but in Include case it's being done in one pass, so overally it's outperform your approach.
You can compare these approaches yourself using Sql Profiler tool.
Update:
Based on conversations I realized that the main issue of Johnny is just existence of OrganizationUsers object. So I suggest to change your approach from DB First to Code first then this object explicitly could be exist! See this to help you on this way
Also another approach that I guess maybe work is customizing T4 Template that seems harder but not impossible!

How to fetch an object with find while also including another object?

I have to fetch an object like this
var fetchedObject = ds.Products.Find(id);
But I also need to add a Include() because Products contains a Supplier object. The code I was given was like
var fetchedObject = ds.Products.Include(“Supplier”).SingleOrDefault(i => i.Id == id);
How would I combine the two so I Find(id) while also Include("Supplier")?
I don't understand what your question is? Your second line of code there is "finding" the object with that id and also including the supplier. I think you might be misunderstanding what Include does. Include means that it will only make one round trip to the database and will retrieve the navigation property "Supplier" along with it so that this can be queried in the next line by doing something :
var supplier = fetchedObject.Supplier;
or whatever you want to do with it. Have you tried running your second line?
If you didn't write the include clause in there then the Supplier of fetched object would be lazily evaluated. That would mean that it would have to make another trip to the database if you ever decided to use Supplier.
You can't. Find does some optimizations that conflict with things like Include. Namely, find will always return the object from the local store without issuing a query if it already has been pulled from the database.

Updating record with EF 5 without loading it first

I have a WebApi application and i am working on some POST/PUT methods and i am trying to figure out the optimal way of updating a record in the database using entity framework.
The main issue with using WebApi is the request will only have a subset of the full properties of the full object.
For instance, i have a Site object that has a Project navigation object that points to the related project. As currently sites cannot move projects, i don't supply the projectId with the PUT command meaning that Project object of Site is empty, which causes issues when trying to update (even when stating that that property is not modified), so i have been forced to reading the record first and then merging the changes and then persisting, like:
Clarity for the example below, site is the object passed as a parameter to the PUT route so in this case is the partial Site object
//Grab the existing site
var dbSite = (from s in _repo
where s.Id == id
select s).FirstOrDefault();
//Update unchanged values
site.Id = id;
site.CreatedOn = dbSite.CreatedOn;
var entry = _uow.Entry(dbSite);
entry.Property(e => e.Code).IsModified = true;
entry.Property(e => e.Active).IsModified = true;
entry.Property(e => e.CreatedOn).IsModified = false;
_uow.Entry(dbSite).CurrentValues.SetValues(site);
//Commit
_uow.Commit();
Is there a way with taking a partial object (without certain navigation properties set) and updating the database without loading it first, or is the best approach loading it and updating the way i am doing it currently?
You've discovered that you need more normalization in your entities as you have a logical relationship between Site and Project, but the relationship is not always needed.
To get the granularity of the entities that you want, you'll have to change the direct relationship between Site and Project to a many-to-many cross reference table so that you can work on a Site without any ties to Project.
Site:
ID
SiteProjectRef:
SiteID (Site.ID)
ProjectID (Project.ID)
Project:
ID
The alternative is, of course, to load the Site and merge the contents before updating. But you stated that you didn't want to go there.

Self join not including children (entity framework 4.0)

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

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