Entity Framework 6 eager loading - c#

I need to load entities from a table into the local cache to display them in a grid control in the application window. The grid control gets its data from the Local property of the DbSet<>. The entities have a collection of subentities which also need to be loaded in advance because lazy loading won't work on the Local entities somehow.
The entity class has all mapped properties virtual and extended change tracking proxies are being used.
Here's what I've found:
myContext.Components.Include(x => x.Parts).ToList();
This is not supported, in fact the compiler throws an error because there is no Include overload that accepts anything else than a string. I have no idea why everybody shows code with expressions here if EF doesn't offer that. So here's what I've done instead:
myContext.Components.Include("Parts").ToList();
Unfortunately this has no effect at all. When I look into the Parts list, it's always empty:
var firstEntity = myContext.Components.Local.First();
var count = firstEntity.Parts.Count;
// count should be > 0 but is = 0
Specifying a different, nonexisting path for the Include method throws an exception at runtime, so EF really does look at that path string and validates it.
After accessing the Parts list, some time later, the parts will be in the list, but that's too late, and I don't know where they come from.
So what's the thing with the expression-parameter Include method, and why doesn't it work at all? What else do I have to consider to use eager loading?
Entity framework 6.1.3 (most other content seems to be for older versions).
Here are the classes:
public class Component
{
[Key]
public virtual int ComponentId { get; set; }
public virtual IList<Part> Parts { get; set; } = new List<Part>();
}
public class Part
{
[Key]
public virtual int PartId { get; set; }
public virtual int ComponentId { get; set; }
public virtual int RequiredCount { get; set; }
}

Related

EntityFramework 6 DatabaseFirst disable lazy loading

How disable all lazy loading
After generation model from database first I have
public partial class company
{
public int id { get; set; }
public string name { get; set; }
public virtual ICollection<user> user { get; set; }
}
public partial class user
{
public int id { get; set; }
public int company_id { get; set; }
public virtual company company { get; set; }
}
I want load only user and their company
db = new Entities();
db.Configuration.ProxyCreationEnabled = false;
db.Configuration.LazyLoadingEnabled = false;
var result = db.user.Include(x => x.company).ToList();
I don`t want load result[0].company.user
Now collection filled with all users of company
result[0].company.user must be null
if i want load result[0].company.user I want use .Include(x => x.company.user)
This is not lazy-loading but a different concept called relationship fix-up. In short it just keeps navigation properties in sync with each other. In your case you have user.company navigation property and company.user collection navigation property. You load both user and company and they are attached to the context. Now at certain points (list of such points you can find here) EF performs relationship fix-up. In this case it happens after query is performed against DbSet. EF ensures that if user.company is set - company.user collection should contain that user also, because those are related navigation properties. This user is already attached to the context (you originally loaded it with your query) so no additional queries are made to database, so it's not lazy loading.
With lazy loading, if you have 100 users for company A then companyA.user will contain 100 entries (loaded from database when you access this property). In your case, even if company A has 100 users - companyA.user will contain just 1 user - that one which you originally loaded.
This behaviour is usually fine, though in some cases it might cause troubles - most often this happens when you want to serialize your EF object and step into circular references because of that.
There is no way to disable this behavior that I'm aware of.

Entity framework 'include' including more than it should

I have a class Program:
[Table("Program")]
public class Program
{
[Key]
public long ProgramId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool IsActive { get; set; }
public virtual ICollection<Activity> Activities { get; set; }
public virtual ICollection<User> Users { get; set; }
public virtual ICollection<TimeEntry> TimeEntries { get; set; }
}
The typical usage pattern is to grab a Program and all it's associated Activities. Much less often need Programs and their related Users or TimeEntries.
So, to return json of all the programs and their related activities. I used .Include:
//...
var programActivities = db.Programs.Include(p => p.Activities);
As expected the json emitted has programs and nested activities. Good.
But, it also returned each Program's associated TimeEntries and Users. Didn't expect that! Other articles i've read indicate that you use one .Include for each of the related objects to be returned, so it would follow that if you don't use an .include for an object, you don't get it.
Is there an additional switch or option i have to use to exclude the other related objects?
Don't declare your navigation properties as virtual or disable Lazy Loading behavior. Lazy loading is enable by default and is achieved by creating instances of derived proxy types and then overriding virtual properties to add the loading hook. So, if you want to work with JSON I recommend you turn off lazy loading:
public class YourContext : DbContext
{
public YourContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
}
Now you can load the related entities you want using the Include extension method as part of a query. This behavior is called Eager Loading.
These links can help you to understand better what I explain in my answer:
Loading Related Entities (read the lazy loading section)
Requirements for Creating POCO Proxies
In Entity Framework, when using the Include statement like so db.Programs.Include(p => p.Activities), you are basically ensuring that the navigation property will be eagerly loaded, rather than lazy loaded. Essentially, this means using one database query to get the data for a Program and its related Activites rather than two.
The problem is, what if lazy loading is enabled for the context, any attempt to get the rest of the navigation properties will result in extra database calls. This is probably what's happening when the JSON serializer tries to serialize your Program objects.
In order to prevent this, you should probably look for a way to exclude the navigation properties from being serialized and so they will never be loaded from the database. For example:
[JsonIgnore]
public virtual ICollection<User> Users { get; set; }
[JsonIgnore]
public virtual ICollection<TimeEntry> TimeEntries { get; set; }
This will allow you to keep lazy loading on, while preventing the loading of the rest of the properties. It all depends on your application design, for example if you need to use lazy loading or if your navigation properties need to be exposed occasionally.

DbContext - Best Practice for Saving Child Collections when Working with Disconnected Entities

I'm attempting to separate my DbContext from a winforms application that I'm currently using to better support a multi-user environment as well as an upcoming website. After doing a bit of research I've going with implementing a data access layer (DAL) for the winforms app/website to connect to and having the end-users work with disconnected entities. My question is regarding the best way I would go about saving updates to my entities when one of the entities in a child collection has been updated.
For instance, if I have the following structure (simplified)
public class Company
{
public int CompanyID { get; set; }
public string CompanyName { get; set; }
public ICollection<Employee> Employees { get; set; } // Non-virtual as we aren't lazy-loading
}
public class Employee
{
public int CompanyID { get; set; }
public int EmployeeID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public ICollection<Claim> Claims { get; set; }
}
public class Claim
{
public DateTime ClaimDate { get; set; }
public ICollection Documentation { get; set; }
}
public class Document
{
public byte[] DocumentImage { get; set; }
public string Name { get; set; }
public DateTime CreateDate { get; set; }
}
Inside the winforms application, I have multiple Binding Source's set-up to display the employee's information
For Example:
employeeBinding.DataSource = typeof(Employee); // Eventually set to an IEnumerable<Employee>
claimBinding.DataSource = employeeBinding;
claimBinding.DataMember = "Claims";
documentationBinding.DataSource = claimBinding;
documentationBinding.DataMember = "Documentation";
However, by setting things up like this I'm unable to make calls on the "CurrentChanged" event of each binding source to save each entity since it has changed (unless I have references stored to the previous entity inside the form). So what I have thought to do was something similar to below in the DAL and iterate through each of the child collections.
public void UpdateEmployee(Employee employee)
{
using (myContext context = new myContext())
{
context.Employees.Attach(employee);
context.Entry<Employee>(employee).State = EntityState.Modified;
foreach(var claim in employee.Claims)
{
context.Entry<Claim>(claim).State = EntityState.Modified;
foreach(var doc in claim.Documentation)
{
context.Entry<Document>(doc).State = EntityState.Modified;
}
}
context.SaveChanges();
}
}
However, I feel that this route can get ugly quick with some more complex entities and relationships. Could someone help point me to the best route to handle this or should I have references to the current entities in the code so when the "CurrentChanged" event fires I can just update each individual entity?
Thank you very much.
When you work with Entity Framework you have the ChangeTracker, even if you are using this "Disconected entities" you can have the ChangeTracker tracking the entities, to have this you just need to attach them to the context and before you call the SaveChanges you call .DetectCHanges() You dont really need to have this specific code, you can use generics for this:
public void Update<TEntity>(TEntity entity)
{
using (myContext context = new myContext())
{
context.Set<TEntity>.Attach(entity);
context.ChangeTracker.DetectChanges();
context.SaveChanges();
}
}
the call to the method would be:
Update<Employee>(employees);
Also i think is better for you to use a BindingSouce as the DataSource, and set the DataSource of the BindingSource as a List instead of typeof(Employee)
I could be wrong but I don't believe DetectChanges will be able to determine that there have been changes made to a disconnected entity. When the entity is attached, it will have an EntityState of "Unchanged" so wouldn't the DbContext do nothing with it until you mark it's state as "Modified". Also, as indicated in the following URL, "DetectChanges" is called for a number of methods (including "Attach") anyways and the explicit call would not be needed.
http://msdn.microsoft.com/en-us/data/jj556205.aspx
As for the BindingSource, I was illustrating that that BindingSource will be set to typeof(Employee) as if I was setting up my code in the constructor before the load events where I would actually get my data and set it's datasource to an IEnumerable from the DAL call. If I didn't do this, I would run into issues when attempting to bind to the "DataMember" properties as the other BindingSources wouldn't be able to find the properties indicated.
I don't believe that the code you provided as a sample fixes the issue I'm running into regarding child collections being updated. When testing with LinqPad they'll be updated if the parent entity has changed as well, but not if there have been zero changes to the parent. That's why I was iterating through all child collections and marking them as "Modified".

How to only get one level deep with EntityFramework 5 on navigation properties?

Right now I have proxy creation disabled:
context.Configuration.ProxyCreationEnabled = false;
I have a data model like so (removed non-relevant fields):
public partial class Video
{
public int VideoID { get; set; }
public string Title { get; set; }
public int UserID { get; set; }
public virtual User User { get; set; }
}
public partial class User
{
public User()
{
this.Videos = new HashSet<Video>();
}
public int UserID { get; set; }
public string Username { get; set; }
public virtual ICollection<Video> Videos { get; set; }
}
I am using Unit of Work and Repository patterns to load my data like so,
Get all video's, including the user object:
var videos = videoService
.Include(v => v.User)
.Get()
I am using automapper to map from data model to domain model (hence the UI namespace in the screenshot below). When I inspect the video enumeration I get back, and look at the first item in the enumeration, I go to check the user object:
What I expect here is the VideoModel to be filled with data(ok), with only it's single UserModel entity to be filled with data(ok), and all collections in the UserModel to be empty(this is broke). As you can see in the second red box above, the Videos collection is populated with 6 videos. And on those video's, the user's are filled in. So this basically creates a very large object graph.
1) Can I make it so when using an include that it ONLY goes 1 level deep (IE doesn't fill in Video.User.Videos)?
2) Why doesn't ProxyCreationEnabled = false take care of this? Am I expecting too much?
p.s. I want to avoid creating a customer mapper for this with automapper.
p.p.s. I am doing db first, not model first
By default, EntityFramework uses lazy loading for virtual properties (such as User and Videos in your example). If you want these properties to be filled prior to them actually being accessed, you can use Include() or, to go another level deep, an Include() with a nested Select().
This default behavior, however, relies on the creation of a proxy class, which you have apparently turned off.
Not knowing all the things you're trying to do, this may not work, but it seems like you would get the behavior you wanted by simply removing ProxyCreationEnabled = false and using Include() as you have.
Also, viewing properties in the debugger may be misleading because you are in fact accessing the property when you try to view it in the debugger (which could cause the lazy loaded entity or collection to be filled right then, making you think it had been eagerly loaded).

Dynamic Expression for Ordering Child Collections with Entity Framework

I am new to EF. I am trying to get Entity Framework 4.2 to do a sort by a calculated property (not mapped).
Here is what my entity look like:
public class Site : Entity
{
public Site()
{
Equipments = new HashSet<Equipment>();
Forecasts = new HashSet<Forecast>();
}
[StringLength(8)]
public string Number { get; set; }
[StringLength(50)]
public string EquipmentShortCLLI { get; set; }
[StringLength(50)]
public string Location { get; set; }
public virtual Central Central { get; set; }
public virtual ICollection<Equipment> Equipments { get; set; }
public virtual ICollection<Forecast> Forecasts { get; set; }
#region Calculated Items
public bool IsEmbargo {
get { return Equipments.Count > 0 && Equipments.SelectMany(x => x.EquipmentDetails).Any(e => e.IsEmbargo); }
}
//...
public int PortsCapacity
{
get
{
return Equipments.Count > 0
? Equipments.SelectMany(x => x.Slots).Sum(x => x.PortsCapacity)
: 0;
}
}
#endregion
//...
By trying to order using any of my readonly properties I am getting the exception:
The specified type member 'PortsCapacity' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.
Which makes sense because EF is trying to build an sql orderby with a field that does not exist in the database (my understanding..).
Now, by using some dynamic linq code I was able to make this work for my many-to-one columns by passing "Central.SomeField" (as opposed to making a ReadOnly Property that returns Central.SomeField).
I.E.:
query.OrderBy("Central.SomeField");
However, I still face the same issue when it comes to a collection of items (Equipments). I am trying to make this as dynamic as possible by using a string coming from the client side and avoiding a long switch case, but at this point I will accept any ideas, so long as the sorting happens on the database side.
Edit 1:
Following what Ladislav Mrnka says, how would one execute an OrderBy clause on one-to-many child items using lambdas or expression?
I don't think that Dynamic Linq is capable of this. You need a real Linq subquery to compute aggregations on Equipements so it will simply not work. If the user selects ordering by IsEmbargo or PortsCapacity you must have some switch / if block to handle this case by appending special part of the query - no other way.

Categories

Resources