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.
Related
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; }
}
Consider the following (very simplified) entities:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Answer
{
public int Id { get;set; }
public virtual User User { get; set; }
public string Text { get;set }
}
public class TeamMember
{
public int Id { get;set; }
public virtual User User { get; set; }
public string Role { get; set; }
}
In my mapper I can set the User fine, but as soon as the following code is executed (before any changes are persisted in the DB)
if (teamMembers.Select(x => x.User).Contains(currentUser))
where teamMembers is a list of TeamMembers and currentUser is a User entity loaded from the Db, then the User property of Answer is set to the previous value from the database.
My understanding is that since I haven't accessed the User property of Answer before it hasn't been loaded from the database yet, and this is what happening (it's been lazy loaded?).
I could fix it by reading the User before even setting it in the mapper but what I cannot understand is why when I access the User property of TeamMember the User property of Answer is loaded and set? Is this expected behavior since both entities are associated with the same User (i.e. in the database they have the same User_Id as a foreign key) and when loading it for TeamMembers, EF tries to be clever and populate other entities that references it and haven't been loaded yet?
The entities aren't stored/cached by the elements that have references to them but are stored with their own respective collections.
Once you loaded that User through the teamMembers reference, it was loaded... period. When you went to reference it from another element/object, it would be silly for it to go and load it again when it already has that object in memory.
This is all by design and it makes sense... if, for example, you wanted to save all these objects at the same time, it would first create the user, get an identity/key for it, then save the other objects that reference it with that key that was generated.
ref: https://msdn.microsoft.com/en-us/data/hh949853.aspx#3
"...the ObjectContext will check if an entity with the same key has
already been loaded into its ObjectStateManager. If an entity with the
same keys is already present EF will include it in the results of the
query. Although EF will still issue the query against the database,
this behavior can bypass much of the cost of materializing the entity
multiple times."
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.
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).
I am using MVC.NET web api, EF with DB first, and I have lazy loading turned off on my context. EF is returning way too much data, even with LazyLoading turned off.
For example, I have Users with one Role. When I query for Users and Include Role, the Role.Users property is automatically filled with data since Users have been loaded into the context.
Why can't I get EF to give me JUST what I request? Or am I missing something big here?
public partial class User
{
public int UserID { get; set; }
public string Title { get; set; }
public string Email { get; set; }
public int RoleID { get; set; }
....
public virtual Role Role { get; set; }
}
public partial class Role
{
public int RoleID { get; set; }
public string RoleName { get; set; }
....
public virtual ICollection<User> Users { get; set; }
}
return db.Users.Include(u => u.Role);
// ^^ user.Role.Users is filled with 1000s of users
TL;DR - I want EF to never load data into navigation properties/collections unless I .Include() it directly. When serializing to JSON I want just what I ask for explicitly. It seems that even with lazy loading off, navigation properties that are already in the context (ie usually "circular references") will be loaded and returned.
The behaviour your are seeing is called Relationship Fixup and you cannot disable it.
If you are loading users with roles to serialize them and sent them to somewhere I guess that you don't want to track changes of entities in the context they have been loaded in. So, there is no need to attach them to the context and you can use:
return db.Users.Include(u => u.Role).AsNoTracking();
Or use a projection into an object specialized for serialization, as suggested by #STLRick.
You can select only what you need by using Select().
var users = _db.Users.Select(x => new
{
UserID = x.UserID,
Title = x.Title,
Email = x.Email,
RoleID = x.RoleID
}).AsEnumerable();
You are right that with lazy loading on, you will get back navigation properties because they are "touched" by the serializer which causes them to be loaded. Lazy loading should be off if you want the properties to come back as null. That said, it "seems" that once entities are loaded into the context (through other queries, for example), they will be processed by the serializer. So the answer is to tell the serializer not to return the navigation properties. The best way I've been able to find to do this is to use DTOs (Data Transfer Objects). This allows you to return exactly the data you want rather than your actual entities.
Your DTO might look something like this:
public partial class UserDto
{
public UserDto(user User)
{
UserID = user.UserID;
Title = user.Title;
//... and so on
}
public int UserID { get; set; }
public string Title { get; set; }
public string Email { get; set; }
public int RoleID { get; set; }
//exclude the Role navigation property from your DTO
}
...and then you could do something like this:
return db.Users.Include(u => u.Role).Select(user => new UserDto(user));
I don't want it to load anything besides what I tell it to include.
It looks like you need to use Explicit Loading. Basically, you could load the specific entities like this:
context.Include("Roles")
To my best knowledge that should not include related entities. Lazy loading should indeed be disabled and you could load navigational properties explicitly with Load.
First: Turn Lazy Loading on.
Second: If you want to filter down what you retrieve and return, then do a custom return object or something.
from u in db.Users
join r in db.Roles
on u.RoleID equals r.RoleID
select new { u.UserID, u.Title, u.Email, r.RoleName }
Or something like that. You will have a minimal return object and your object graph will be tiny.