I have two objects that have a many to many relationship with each other.
I'm using Entity Framework in a Database First approach.
My Database Profiler is showing that everytime I fetch one set of objects A, it loads the other set of object B for each element in A. I assumed that with lazy loading, this wouldn't happen, or that B would be fetched when accessing via the navigation property.
The code to access the objects uses a generic approach, where entities is my DbContext
public virtual IQueryable<T> GetAll()
{
IQueryable<T> query = entities.Set<T>();
return query;
}
Both navigation properties are implemented as virtual ICollection<T> and I have Configuration.LazyLoadingEnabled = true explicitly set in my DbContext constructor.
Am I missing something, or approaching this the wrong way? Should I just remove the navigation properties and explicitly load what I need via other queries?
In the presence of the experts I am reluctant to ask this :) but would setting ProxyCreationEnabled=false on the DbContext not help in this case? Sorry if this is too "newbish" of a point
Related
I've seen this question asked a million times, but every single suggestion I've encountered I already seem to have covered.
I have entity framework in my MVC solution, and I have a 'repository' which attempts to retrieve a collection of MyObjects:
public static List<MyObject> GetMyObjects()
{
using (var context = new MyEntities())
{
return context.MyObjects.Include("Contact").OrderByDescending(o => o.Date).ToList();
}
}
I call this method as part of a controller action which attempts to serialize it:
public JsonResult All()
{
return Json(MyRepository.GetMyObjects(), JsonRequestBehavior.AllowGet);
}
And I get the following error:
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
I don't know where to turn on this one, I appreciate entity framework 'lazy-loads' relational data sets if and when they're needed, and I appreciate attempting to serialize the whole collection would indeed attempt to load these (outside of the using statement), but I have the 'Include' there.
What I've Tried
I've tried the 'include', I've also ensured no other associations are part of the MyObject class (i.e. I have no other Include()s to write).
To avoid this you have some options.Don't declare your navigation properties as virtual or disable Lazy Loading behavior on your context. 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 a serializer I recommend you turn off lazy loading:
public class YourContext : DbContext
{
public YourContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
}
These links can help you to understand better what I explain in my answer:
Loading Related Entities
Requirements for Creating POCO Proxies
If you remove the virtual keyword from your navigation properties, the POCO entity not meet the requirements described in the second link, so, EF won't create a proxy class to lazy load your navigation properties. But if you disabled lazy loading, even when your navigation properties are virtual, they won't be loaded in any entity. It's good idea disable lazy loading when you are using a serializer. Most serializers work by accessing each property on an instance of a type.
As a third option you could use the JsonIgnore attribute on your navigation properties that you don't want to be serialized as part of your entity, but as I said before, the best option is disable lazy loading.
When you use Include and using Lazy loading, and wrap the dbContext in a Using statement, then once it tries to get the linked objects, the dbContext is already disposed.
You can try eager loading of the navigation property like this:
IQueryable<MyObjects> query = db.MyObjects.Include(m => m.Contact);
Or you could take out the Using statement, as it is limiting your lazy loading...
I had the same problem and solved like below;
I created a new object and put the values I am gonna use after getting object from db.
Example Code:
var listFromDb= db.XTable.Where(x => x.Id > 5).ToList();
var list = new List<Package>();
foreach (var item in listFromDb)
{
var a = new Package()
{
AccountNo = item.AccountNo,
CreateDate = item.CreateDate,
IsResultCreated = item.IsResultCreated,
};
list.Add(a);
}
I have two tables, Kittens and Owners in my Entity Framework model. A Kitten has 1 Owner but an Owner can have many Kittens.
I have a repository method called GetKittens() that returns _context.Kittens.ToList();
Since I set up an association, I can do kitten.Owner.Name.
But since ToList() was already called, and the context disposed of, how does it access the property? When retrieving an Entity, does it do a Join to all tables that have an association?
I have to write a query that pulls data from 4 tables, so I am wondering how to do this efficiently, hence this question trying to understand a bit more about how EF works.
By default, a DbContext will use lazy loading. There is a few options available to you, depending on your use cases.
1- If you have control over the lifetime of your DbContext, do not dispose it. However, every time you will access a related entity (for the first time), a new query will be sent to the database to fetch it.
2- Eagerly include the related entity by use Include on the IQueryable<Kitten>:
// For imagine context is the DbContext for your EF Model
context.Kittens.Include(c => c.Owners); // Or Include("Owners")
However, if you have no control over your repository, you have no option but to call a related method of your repository (like IEnumerable<Owner> GetOwners(Kitten kitten)) since the repository already returns the list.
If you do, consider either eagerly include the Kitten's owners in the repository before materializing with ToList() or return an IQuerable and leave the responsibility to the calling class to include related entities or customizing the query. If you do not want a caller to be able to alter the query, you can add an overload with includes that could be something along the line of:
public List<Kitten> GetKittens(params string[] includes)
{
return includes.Aggregate(
context.Kittens.AsQueryable(),
(query, include) => return query.Include(include)).ToList();
}
All in all, this is an implementation decision that you will have to take.
Please help me, I am new to EF.Lazy loading for POCO objects doesn't seem to be working.
My POCO classes are in a sepearte assembly, other than the one one for Data access(i.e DAL)
The Data Acess layer simply wraps the calls made to the EF's object context. Please see the code below
public FilterMaster GetFilter(long ID)
{
FilterMaster entity = new FilterMaster();
try
{
using (var context = new RadarEntities())
{
//context.ContextOptions.LazyLoadingEnabled = false;
//context.ContextOptions.ProxyCreationEnabled = true;
entity = context.FilterMasters.SingleOrDefault(filter => filter.ID == ID);
//context.FilterMasters.Include(
context.LoadProperty(entity, "SQLQuery");
}
}
When DAL call is completed, the ObjectContext is lost, and when I tried to fetch the related child objects of the Root POCO class, I get null.
I've tried explicitly enabling ProxyCreation, EnabledLazyLoading, checked the proxy clases generated are not sealed and all the related properties are marked virtual (as suggested on some other links).
-As the lazy load was not working, I thought of eagerly loading all the related POCO objects, so tried invoking LoadProperty method, which works.
Q1: Am I Imissing something the lazy loading isn't working?
Q2: If I want to expelictly load all the related child objects the will have to call the LoadProperty method for all properties or there is any simpler way?
You are disposing your ObjectContext. This is what is preventing you from using LazyLoading. If you need LazyLoading, the class containing GetFilter should create an ObjectContext when it is created, implement IDisposable, and dispose of the ObjectContext when it is disposed.
Q1: Am I Imissing something the lazy loading isn't working?
It's working but there is no magic involved - underneath a proxy is created for you which will try to retrieve the property value from the database for you on the first access.
For EF the database connection is represented by the context, which you currently dispose automatically at the end of your using block. Without database connection EF cannot lazily retrieve the properties and hence lazy loading won't work.
You will have to keep the context alive until you have accessed all the properties you need to access for lazy loading, or alternatively eagerly load those properties.
Q2: If I want to explicitly load all the related child objects the
will have to call the LoadProperty method for all properties or there
is any simpler way?
Yes, you can specify an Include() query to eagerly retrieve properties, in your case that would be:
entity = context.FilterMasters
.Include("SQLQuery")
.SingleOrDefault(filter => filter.ID == ID);
I'm using EF 4.1 and code-first in an MVC project, and AutoMapper to map entities to view models.
Prior to using code-first I was able to exclude navigation properties in order to prevent anything from being loaded that wasn't already. I'm using .Include() in my queries to include the references that I need in order to avoid additional database round-trips.
However, with code-first my entity only exposes an entity property (or ICollection if there are more than one). How can I know whether it has been loaded without triggering the load?
Assuming this can be done, is there a way to make this the default behavior for AutoMapper, so that I do not have to explicitly exclude members on every single entity?
You can check whether a reference or collection navigation property of an entity has been loaded by:
bool isLoaded1 = dbContext.Entry(entity).Reference(e => e.MyReferenceProperty)
.IsLoaded();
bool isLoaded2 = dbContext.Entry(entity).Collection(e => e.MyCollectionProperty)
.IsLoaded();
EF Code First does lazy loading only for properties marked as virtual (it can override those and place DynamicProxy instead of it). If you don't make your property virtual, you will turn off lazy loading for that property.
You should be able to explicitly load them by turning off lazy-loading:
using(var context = new FooBarEntities())
{
context.ContextOptions.LazyLoadingEnabled = false;
Foo foo = context.Foo.Where(x => x.Id == myId).Single();
...
if(!foo.Bars.IsLoaded)
{
foo.Bars.Load();
}
//do something with foo.Bars here
}
Basically, I need to set a property to the results of a query that uses data from the parent object.
With the domain model below, I need to set the C property of EntityB using data from both EntityA and EntityB.
Also, I need to set the A property of EntityB to be the actual instance of EntityA that is its parent.
Query:
Set EntityB.C = (select * from EntityC where SomeProperty = EntityB.SomeProperty and AnotherProperty = EntityB.A.AnotherProperty);
SomeProperty and AnotherProperty are not just keys.
class EntityA
{
public IList<EntityB> B
{
get;
set;
}
}
class EntityB
{
public EntityA A
{
get;
set;
}
public EntityC C
{
get;
set;
}
}
class EntityC
{
...
}
I need a way to execute code (to run the query and assign to property) for each entity returned. I came close using the onload method of an interceptor, but I am looking for another way. Perhaps using a Result Transformer or a Projection?
First of all, if you're using NHibernate properly, the properties and associations should be automatically done for you by the framework. If they're not, then you don't have it set up correctly...
As for doing a query in a property... this is usually not recommended (abstract it into a utility class, or at the very least a function call), but I do remember seeing some way on here how to do it.
There are actually two questions.
Question 1: How to have a property that is loaded by some query?
Ask your self if it really needs to be in the entity. Consider to have a DTO (data transfer object) that holds data from different entities and queries instead.
If you're sure that you need this property in the entity, take a look at formulas for single ended properties and filters for collections.
I can't provide more detailed information, because your question is highly general, and it depends on the actual problem. But you should find a solution by starting with the given links.
Question 2: How can I have a property pointing to the parent?
Very easy: By just implementing the property and map the collection of children (B) "inverse=true". Implement your entities the way that they consistently point to the correct parent.
Why is NH not doing this for you? Because NH's responsibility is only to persist your entities to the database. NH does not make any changes on the data by its own. This is responsibility of your business logic.
Note: your application should also be able to run without NH, eg in a unit test. So relations should be managed in your code.