Linq to entities lazy loading - c#

I have the following class generated by entity framework:
public partial class Branch
{
public short Id { get; set; }
public short CompanyId { get; set; }
public string Code { get; set; }
public string Title { get; set; }
public virtual Company Ts_Companies { get; set; }
}
I have the following method which takes all of the branches out of the database:
public Branch[] LoadBranches(int companyId, int page, int limit, string search, string sort, string sortOrder)
{
using (var dbContext = new TimeShedulerEntities())
{
var _branches = (from ct in dbContext.Branches
where ct.Title.Contains(search) || ct.Code.Contains(search)
select ct).OrderBy(c => c.Title).Skip((page - 1) * limit).Take(limit);
return _branches.ToArray();
}
}
In my model designer I see that the Lazy Loading is set to true, but when I iterate over the branches, the property Ts_Companies is null. Also I get the following exception:
An exception of type 'System.ObjectDisposedException' occurred in
EntityFramework.dll but was not handled in user code
Additional information: The ObjectContext instance has been disposed
and can no longer be used for operations that require a connection.
Am I forgetting something?

You created and disposed of the context during your function since it was inside the using statement. Each entity happens to know from which context it was created so that lazy loading is possible.
When you accessed the Ts_Companies property, the entity realized that it had not yet loaded that property since it is probably a navigation property and attempted to ask its ObjectContext (TimeShedulerEntities) to load that property. However, the context had been disposed and so that it what caused that exception.
You need to modify your query as follows to 'pre-load' the Ts_Companies:
var _branches = (from ct in dbContext.Branches.Include("Ts_Companies")
where ct.Title.Contains(search) || ct.Code.Contains(search)
select ct).OrderBy(c => c.Title).Skip((page - 1) * limit).Take(limit);
It will take possibly quite a bit longer to load depending on the size of the Ts_Companies object and how many you end up bringing back at once, but the entity will stop asking its object context to load the Ts_Companies since you would have already loaded them.
A side note: I have found that creation and disposal of object context on a per-method basis causes problems when the entities are passed outside the function. If you want to create and destroy the object context in every function, you probably want to have the function return something that is not an entity. In other words, have an object that can be constructed from an entity and has the properties you need, but don't have it reference the entity. In java these are often called Data Transfer Objects (DTOs). You lose the read-write ability of entity framework, but you don't have unexpected ObjectDisposedExceptions flying all over the place.
The problem comes when you ask an entity to be associated with another (for example, adding on entity to a ICollection property of another entity) when they come from different objectcontexts. This will cause headaches for you since you would have to manually attach the objects to the same context before performing that operation. Additionally, you lose the ability to save changes to those entities without manually attaching them to a different context.
My opinion on how I would do it:
I've found it easier to either have an object containing all of these database access functions control the lifetime of the context (i.e. have your containing object be IDisposable and during disposal, destroy the context) or simply not return entities and have the datastore be read-old, write-new essentially without any modification ability.
For example, I have my object (I will call it my data access object) with a bunch of methods for getting database objects. These methods return entities. The data access object also has a SaveChanges method which simply calls the context's SaveChanges method. The data access object contains the context in a protected property and keeps it around until the data access object itself is disposed. Nobody but the data access object is allowed to touch its context. At that point, the context is disposed by manually calling 'Dispose'. The data access object could then used inside a using statement if that is your use case.
In any case, it is probably best to avoid passing entities attached to a context outside the scope in which their context exists since entity framework keeps references to that context all over the place in the individual entities

But you didn't load your Ts_Companies, use Eager Loading instead:
var _branches = dbContext.Branches
.Where(b => b.Title.Contains(search) || b.Code.Contains(search))
.Include("Ts_Companies")
.OrderBy(c => c.Title)
.Skip((page - 1) * limit)
.Take(limit);
And I came across the same issue before System.ObjectDisposedException, in my MVC project and I didn't use using blocks,instead I define my context on class level.If I need to return and use an array (in my View) I use that context.If I need to just update some information then I have used using blocks.I hope this helps.

Related

When retrieving a set with EFCore, why do the retrieved entities not include their relationships to other objects?

While using Entity Framework Core with SQL Server I encountered an unexpected problem. I have an entity A that has a one-to-many relationship on entity B.
[Table("client")]
public class Client
{
public long ID { get; set; }
public string Name { get; set; }
public ICollection<Configuration> Configurations { get; set; } = new LinkedList<Configuration>();
}
I get a list of instances of entity A from the database like this:
public ICollection<Client> GetAllClients()
{
return _dbContext.Clients.ToList();
}
When I call this function I get a list of instances without the instances of entity B in the relationship. Why are the objects in the relationship not retrieved correctly?
I've also found out that if I add this line of code to the function the entities are retrieved as expected.
public ICollection<Client> GetAllClients()
{
var test = _dbContext.Configurations.ToList();
return _dbContext.Clients.ToList();
}
This makes no sense to me. What am I missing here?
You can use the Include method to specify related data to be included in query results (Eager loading).
Take a look in the following example:
public ICollection<Client> GetAllClients()
{
return _dbContext.Clients.Include(x => x.Configurations).ToList();
}
You can check the MSDN reference.
Related reference/collection properties must either be eagerly or explictly loaded. You generally want to eagerly load using Include:
var clients = await _context.Clients.Include(x => x.Configurations).ToListAsync();
Alternatively, you can lazy load, but that's generally a bad idea, as it can lead to N+1 query problems (i.e. you issue one query, and then a separate additional query for each item as you iterate through, which is obviously highly inefficient). Regardless, lazy loading requires two things:
The reference/collection property must have the virtual keyword. EF adds lazy loading functionality by creating a dynamic proxy of your entity class and overriding the property getter. Overriding, of course, can only be done on virtuals.
You have to explicitly add the lazy-loading services:
services.AddDbContext<MyContext>(o => o.UseLazyLoadingProxies()
.UseSqlServer(connectionString));
It works when you query the configurations as well, because EF has object-fixup. In other words, it will automatically fill related reference/collection properties, if it has previously retrieved those objects already and has them in its object cache. Otherwise, and if you do not otherwise load the relations, the property will remain null.

Does EF6 virtual navigation property result into SQL query?

Assuming that I have an entity with virtual nagivation property like this:
public class School
{
public long Id { get; set; }
public virtual ICollection<Students> Students { get; set; }
}
As I understand, EF6 uses proxy to enable lazy-loading of Students, but do the following LINQ queries:
var myStudent = this.Students.Single(x => x.Id == id);
var studentsCount = this.Students.Count();
var bestStudents = this.Students
.OrderByDescending(x => x.GPA)
.Take(5)
.ToArray();
result into a SQL query (just like IQueryable<T> does)? Or is it just a lazy-loading collection and will load all students into memory after the first request, and then perform simple IEnumerable<T> LINQ behaviour?
When you query for an entity in Entity Framework, the objects that get returned are not (always) the type of object you think they are. Behind the scenes, it creates a brand new class that inherits from the your class. Because OOP allows a subclass to be stored in a variable typed as the superclass, you never really notice. This is the "proxy" that you mention. That's why the virtual function allows lazy loading. The subclass overrides your virtual method, and contains the code to lazy load the extra data before returning it.
That overridden property call will then check the context to see if the navigation properties are already loaded. If they are, it just returns them. If they are not, it will make additional SQL calls to load them, storing them in the DbContext for later.
In your updated question, my understanding is that running those lines of code would result in 3 separate queries being executed.
Public virtual properties are lazy loading in EF6.
You can disable lazy loading for a DbContext, or use the .Include() method on the IQueryable to include the property in the first query.
http://www.entityframeworktutorial.net/EntityFramework4.3/lazy-loading-with-dbcontext.aspx
https://msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx
Once you "iterate" through the list (e.g. by calling the .Single(), .Count() or .ToArray() method), the query is executed and you have a in-memory list of your students. See https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/query-execution for more details about query execution.
The first example would result in 3 queries, where the first returns the student with the given Id, the second returns the student count and the third returns the first 5 students ordered desc by their GPA property.
Regarding DDD => You can use some Layered architecture, with ApplicationServices and DomainServices, where DomainServices perform the domain logic and ApplicationServices load / transform the data.
The https://aspnetboilerplate.com/ template is for example a good starting point for domain driven design.
Assuming that the second code block is executed somewhere INSIDE the scope of an instance of 'School' (so 'this' is an instance of 'School' - in my example below school19) then the following scenarios are possible:
A) You have loaded your instance of 'School' like this (Lazy loading enabled):
var school19 = dbContext.Set<School>()
.FirstOrDefault(school => school.Id == 19)
Then your 3 lines of code for accessing the property 'Students' will trigger a single additional database hit when
var myStudent = this.Students.Single(x => x.Id == id);
is executed, but no more database hits will occur with the subsequent two statements.
B) In case you have loaded your instance of 'School' like this (Lazy loading enabled):
var school19 = dbContext.Set<School>()
.Include(school => school.Students)
.FirstOrDefault(school => school.Id == 19)
Then your 3 lines of code for accessing the property 'Students' will not trigger an additional database hit.
C) If lazy loading was disabled, then
A) would result in a Null Reference Exception
B) would behave the same
As a last remark, if 'this' was a reference to an instance of the DBContext class, which has a property
public Set<School> Schools { get; set; }
then it would trigger 3 different database calls. But the result is different as this would be executed in the context of ALL schools, while my assumptions above only apply to a single school.

How to serialize entity if using lazy loading in entity framework?

I just started to learn entity framework and i am facing the problem related to serialization of generated Models. I have tables with one to many relation which are Country and State as one country have many states. I am using the DB first approach and when i create the entities using Entity Framework, the class Country has one property of ICollection. I read and found that this is the navigation property. Let me show the generated class first which is below:
//This is the generated class.
public class Country
{
public Country()
{
States = new HashSet<States>();
}
public int Id { get; set; }
public string ContryCode { get; set; }
public string ContryName { get; set; }
public virtual ICollection<States> States{ get; set; }
}
I generated Models and then i step forwarded. Then i got the problem of serialization when i request via ajax to get the list for Country. I googled and found some terms like lazy loading, eager loading and n+1 problem. I read about it in detail. I found a solution which was turning off the lazy loading. Now the question is How i can serialize my Model with lazy loading?
I have created MetaData class and use some attribute like ignoreXml etc but nothing helped. By the way i am using Asp.Net MVC 5 and i want to serialize my Model with lazy loading. Can any one explain?
When you use lazy loading, execution is deferred until the value of the property is actually needed. You are probably encountering an error because the context has been disposed by the time the property is accessed. Consider the following scenario:
You have an object called Country with a lazy-loaded property called States.
You get this object from a context.
The context is disposed.
You call the States property.
The property goes looking for the context it came from.
An error is thrown because "the context has been disposed".
Code Sample:
using(var context = new SomeEntityContext())
{
var country = context.Countries.First();
}
//This will throw an error because the context was disposed of.
var states = country.States;
The serializer would also throw an error because it will go through the properties of the object, it will find States and it will try to get its value.
Even if the context is still alive, you could run into a loop with navigational properties during serialization. this is because both objects hold a reference to each other. Consider the following scenario:
You have an object called Country with a lazy-loaded property called States.
The serializer attempts to serializer the object of type Country.
It reads the States collection.
It attempts to serialize every object of type State.
It reads a property of type Country.
It attempts to serialize the object of type Country.
It reads the States collection.
It attempts to serialize every object of type State.
It reads a property of type Country.
It reads the States collection.
It attempts to serialize every object of type State.
It reads a property of type Country.
It reads the States collection.
It attempts to serialize every object of type State.
It reads a property of type Country.
.... (endless loop, well, at least until you run out of stack frames).
Alternatively, you can create a custom serializer that will avoid the pitfalls of navigational properties, but that is probably more work than it's worth. This approach is best suited for situations where the serialized version differs significantly from the object.
This is why you are better off using a Data Transfer Object (DTO). Map the data to this object and send that over the wire. There are components out there that can do the mapping for you, if you keep the structures as similar as possible.
Check out AutoMapper: http://automapper.org/

Attaching and detaching entities from context correctly in EF4.1

I am trying to implement caching mechanism for entities. And to use the entities correctly and seamlessly with the caching i need to detach the entity from the current context before i put it in a cache and attach it back the the new context when i get it from the cache. (My context lifetime is per http request)
The requirements are that -
All the navigational properties that are associated with it (which i have already populated) should not be removed when the entity is detached.
I can update the cached items if i want ( so correctly attaching them to the new context is important).
This is my attempt at creating an EntityCache class - (ServerCache here is my wrapper class that pushes the object to ASP.NET cache)
public static class EntityCache
{
private static DbContext context
{
get
{
return (DbContext)HttpContext.Current.Items[ObjectKeys.ContextRequestItemKey];
}
}
private static void Detach(object entity)
{
var trackedEntity = entity as IEntityWithChangeTracker;
trackedEntity.SetChangeTracker(null);
((IObjectContextAdapter)context).ObjectContext.Detach(entity);
}
private static void Attach(object entity)
{
((IObjectContextAdapter)context).ObjectContext.Attach((IEntityWithKey)entity);
}
public static void Remove(string key)
{
ServerCache.Remove(key);
}
public static object Get(string key)
{
object output = ServerCache.Get(key);
if (output != null)
Attach(output);
return output;
}
public static void ShortCache(String key, object data)
{
if (data != null)
{
Detach(data);
ServerCache.ShortCache(key, data);
}
}
public static void LongCache(String key, object data)
{
if (data != null)
{
Detach(data);
ServerCache.LongCache(key, data);
}
}
}
When i put an entity in the cache it is of type DynamicProxy and NOT the real class.
Attaching doesnt work at all - i get an exception that i cannot case object that is of type Dynamic_{blahblah} to IEntityWithKey.
I just saw these examples of attach and detach online and tried them, I am open to any new implementation of the Attach/Detach methods here.
Thank you.
Follow up question -
context.Entry(entity).State = EntityState.Detached;
Works, but makes all the navigational properties that are loaded NULL, how do we make it keep the navigational properties and NOT replace(or lose) them with NULL when we detach from context.
IEntityWithKey is interface for other types of entities. It is for "big" entities. For example EntityObject implement this interface. These entities are not considered as POCO and are not supported by DbContext API.
If you want to use IEntityWithKey your classes must implement it - it is not something that would happen automatically.
Correct attaching with DbContext API should be:
dbContext.Set(typeof(entity)).Attach(entity);
and this should hopefully also work:
dbContext.Entry(entity).State = EntityState.Unchanged;
Correct detaching with DbContext API should be:
dbContext.Entry(entity).State = EntityState.Detached;
Also it is better to you generic methods instead of object.
To your follow-up question:
...how do we make it keep the navigational properties and NOT
replace(or lose) them with NULL when we detach from context...
I believe it's not possible to detach an object graph from the context while maintaining it's navigation properties. From MSDN:
In an independent association, the relationship information is not
maintained for a detached object.
Although this statement is about independent associations it does not mean that navigation properties are maintained in foreign key assocation (relationships which expose a foreign key property in the model). Yes, "Relationship information" is maintained because the foreign key properties (which are scalar properties) will be alive and contain the correct foreign key value after detaching. But the corresponding navigation properties will still be null for reference properties or, for navigation collections the reference will be removed from the collection.
I think the only way to detach a complete object graph from a context is either disposing the context altogether or create a copy of the graph before starting to detach the original graph. Creating a copy would require writing Clone methods which copy all the properties and navigate through the graph or using a "trick" like this which serializes the graph into a binary stream and then deserializes it back to new objects. For this the entities would need to be serializable. Also reference cycles (which we often have when using bidirectional navigation properties between entities) can cause trouble. (Also attention if your objects are proxies which contain references to EF's internal objects and which you probably don't want to copy, serialize and deserialize.)
In this aspect Detach is not the counterpart of Attach because it behaves quite differently: Attach attaches the whole object graph and maintains navigation properties. Detach detaches only single entities without the related objects and destroys navigation properties. From the same page linked above:
Detach only affects the specific object passed to the method. If the
object being detached has related objects in the object context, those
objects are not detached.
I could imagine that this is the main reason why the DbContext API doesn't have an explicite Detach method (in contrast to ObjectContext) - detaching is considered as an advanced feature which does not behave as one might expect.
MSDN mentions as the only reason to detach an object from the context "to conserve resources" (again the article above):
In Entity Framework applications, you can detach objects from the
object context. You might detach objects to conserve resources, as
executing repeated queries in the same object context increases the
memory requirements of the object context.
I think this method is just not prepared and designed for working with the objects after they've been detached from the context. It's main purpose is to release them for immediate garbage collection.

Entity Framework Multiple Object Contexts

This question has been asked 500 different times in 50 different ways...but here it is again, since I can't seem to find the answer I'm looking for:
I am using EF4 with POCO proxies.
A.
I have a graph of objects I fetched from one instance of an ObjectContext. That ObjectContext is disposed.
B.
I have an object I fetched from another instance of an ObjectContext. That ObjectContext has also been disposed.
I want to set a related property on a bunch of things from A using the entity in B....something like
foreach(var itemFromA in collectionFromA)
{
itemFromA.RelatedProperty = itemFromB;
}
When I do that, I get the exception:
System.InvalidOperationException occurred
Message=The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.
Source=System.Data.Entity
StackTrace:
at System.Data.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper wrappedTarget, Boolean applyConstraints, Boolean addRelationshipAsUnchanged, Boolean relationshipAlreadyExists, Boolean allowModifyingOtherEndOfRelationship, Boolean forceForeignKeyChanges)
at System.Data.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper wrappedEntity, Boolean applyConstraints)
at System.Data.Objects.DataClasses.EntityReference`1.set_ReferenceValue(IEntityWrapper value)
at System.Data.Objects.DataClasses.EntityReference`1.set_Value(TEntity value)
at
I guess I need to detach these entities from the ObjectContexts when they dispose in order for the above to work... The problem is, detaching all entities from my ObjectContext when it disposes seems to destroy the graph. If I do something like:
objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged)
.Select(i => i.Entity).OfType<IEntityWithChangeTracker>().ToList()
.ForEach(i => objectContext.Detach(i));
All the relations in the graph seem to get unset.
How can I go about solving this problem?
#Danny Varod is right. You should use one ObjectContext for the whole workflow. Moreover because your workflow seems as one logical feature containing multiple windows it should probably also use single presenter. Then you would follow recommended approach: single context per presenter. You can call SaveChanges multiple times so it should not break your logic.
The source of this issue is well known problem with deficiency of dynamic proxies generated on top of POCO entities combined with Fixup methods generated by POCO T4 template. These proxies still hold reference to the context when you dispose it. Because of that they think that they are still attached to the context and they can't be attached to another context. The only way how to force them to release the reference to the context is manual detaching. In the same time once you detach an entity from the context it is removed from related attached entities because you can't have mix of attached and detached entities in the same graph.
The issue actually not occures in the code you call:
itemFromA.RelatedProperty = itemFromB;
but in the reverse operation triggered by Fixup method:
itemFromB.RelatedAs.Add(itemFromA);
I think the ways to solve this are:
Don't do this and use single context for whole unit of work - that is the supposed usage.
Remove reverse navigation property so that Fixup method doesn't trigger that code.
Don't use POCO T4 template with Fixup methods or modify T4 template to not generate them.
Turn off lazy loading and proxy creation for these operations. That will remove dynamic proxies from your POCOs and because of that they will be independent on the context.
To turn off proxy creation and lazy loading use:
var context = new MyContext();
context.ContextOptions.ProxyCreationEnabled = false;
You can actually try to write custom method to detach the whole object graph but as you said it was asked 500 times and I haven't seen working solution yet - except the serialization and deserialization to the new object graph.
I think you have a few different options here, 2 of them are:
Leave context alive until you are done with the process, use only 1 context, not 2.
a. Before disposing of context #1, creating a deep clone of graph, using BinaryStreamer or a tool such as ValueInjecter or AutoMapper.
b. Merge changes from context #2 into cloned graph.
c. Upon saving, merge changes from cloned graph into graph created by new ObjectContext.
For future reference, this MSDN blogs link can help decide you decide what to do when:
http://blogs.msdn.com/b/dsimmons/archive/2008/02/17/context-lifetimes-dispose-or-reuse.aspx
I don't think you need to detach to solve the problem.
We do something like this:
public IList<Contact> GetContacts()
{
using(myContext mc = new mc())
{
return mc.Contacts.Where(c => c.City = "New York").ToList();
}
}
public IList<Sale> GetSales()
{
using(myContext mc = new mc())
{
return mc.Sales.Where(c => c.City = "New York").ToList();
}
}
public void SaveContact(Contact contact)
{
using (myContext mc = new myContext())
{
mc.Attach(contact);
contact.State = EntityState.Modified;
mc.SaveChanges();
}
}
public void Link()
{
var contacts = GetContacts();
var sales = GetSales();
foreach(var c in contacts)
{
c.AddSales(sales.Where(s => s.Seller == c.Name));
SaveContact(c);
}
}
This allows us to pull the data, pass it to another layer, let them do whatever they need to do, and then pass it back and we update or delete it. We do all of this with a separate context (one per method) (one per request).
The important thing to remember is, if you're using IEnumerables, they are deferred execution. Meaning they don't actually pull the information until you do a count or iterate over them. So if you want to use it outside your context you have to do a ToList() so that it gets iterated over and a list is created. Then you can work with that list.
EDIT Updated to be more clear, thanks to #Nick's input.
Ok I get it that your object context has long gone.
But let's look at it this way, Entity Framework implements unit of work concept, in which it tracks the changes you are making in your object graph so it can generate the SQL corresponding to the changes you have made. Without attached to context, there is no way it can tack changes.
If you have no control over context then I don't think there is anything you can do.
Otherwise there are two options,
Keep your object context alive for longer lifespan like session of user logged in etc.
Try to regenerate your proxy classes using self tracking text template that will enable change tracking in disconnected state.
But even in case of self tracking, you might still get little issues.

Categories