I'm experiencing something rather odd. I'm tinkering with NHibernate 3.2 mapping by code and have a very simple object model I'm using just to play.
None of my properties in the entire model are marked as virtual because I dont want lazy loading. I'm mapping by code and in each class mapping I'm setting Lazy(false);
However when it comes to mapping collections, if I try and access a collection after the session has ended I get an error "failed to lazily initialize a collection of role...".
I have to explicitly set collectionMapping.Lazy(CollectionLazy.NoLazy); before it will eager load the collection. It was my understanding that lazy loading was not possible unless your properties in your model were defined at virtuals?
Have I fundamentally missed something?
virtual is needed more than just for lazy loading. NHibernate requires them to be virtual because it creates a run-time proxy of the class and injects behavior.
Virtual properties and methods are only needed for lazy associations (many-to-one or one-to-one) because NHibnerate needs to set a proxy entity on the association property.
Collections (one-to-many and many-to-many) don't need any virtual properties because only the collection is lazy, not the entities in the collection. NHibernate will always use its own collection classes, even if you disable lazy loading.
You still need to use IList<T> instead of List<T>, because NH needs its own collection implementation.
Consider:
You won't get very far in a complex model without lazy loading, except your database fits into RAM or you don't mind to cut you OO model into pieces which destroys both maintainability and performance.
You can have entities without virtual members when you use interfaces to create proxies from. However, you should only use these interfaces to reference to entities, because they could always be proxies.
Related
My scenario is I have an object FOO which has a virtual List<bar> property on it. This is being auto generated by EF.
After I load FOO I dispose of the data context, I am turning FOO into a business object through a DTO. For example
var newFOO = FOO_Dto.change(FOO);
Inside of FOO_Dto.change I want to check if the virtual list property is empty/null. I understand that closing the ObjectContext and checking the navigation property will throw an error. In My Data Layer there are times when I return FOO with the list and FOO without the list.
My Question is how do I check the Navigation Property to see if the list has been populated or not and avoid the ObjectContext error that is currently generating
Thank you very much!!
EDIT
From the comments section, I purposely want the context closed before I check to see if I loaded the List<Bar> property.
No, you can't, other than the ugly way of trying and catching the exception. You can only determine whether a collection is loaded by getting the owner's DbEntityEntry, which you can only obtain through a context instance.
But if you know up front that the collection may be addressed outside the scope of the context, you need to load it while the context is alive, OR not load it and prevent lazy loading. You should never allow lazy loading to occur outside the lifespan of a context.
In most cases this means you'll have to turn off lazy loading and eagerly load all data required by a consuming method.
The more I work with EF in a disconnected fashion the less I allow lazy loading. I'm close to considering lazy loading an anti-pattern.
I have an entity model with a self relation (parent/child). My entity named Article has a property called parent. This parent is in fact the relation, and ParentID which is the field in the relation. In ef 4 i did this:
using (var dbContext= new DataBaseModel())
{
ArticleTable newEntity= new ArticleTable();
newEntity.name="childArt";
newEntity.ParentID = 1;
dbContext.ArticleTable.Add(newEntity);
dbContext.SaveChanges();
//after calling save I can do this
var parentName = newEntity.Parent.Name;
}
With entity framework 6, this doesn't work any more, I have get the entity from the database again in order to get the related parent entity. Is this because of changes to lazyloading? what should i do different.
The difference is that in EF 4 entities were generated with piles of code that took care of change notification and lazy loading. Since then, the DbContext API with POCOs has become the standard.
If you want the same behavior as with the old 'enriched' entities you must make sure that lazy loading can occur by a number of conditions:
The context must allow lazy loading. It does this by default, but you can turn it off.
The navigation properties you want to lazy load must have the virtual modifier, because
EF must create dynamic proxies. These proxies somewhat resemble the old generated entities in that they are able to execute lazy loading, because they override virtual members of the original classes.
The last (and maybe second) point is probably the only thing for you to pay attention to. If you create a new object by new, it's just a POCO object that can't do lazy loading. However, if you'd create a proxy instead, lazy loading would occur. Fortunately, there is an easy way to create a proxy:
ArticleTable newEntity= dbContext.ArticleTables.Create();
DbSet<T>.Create() creates dynamic proxies -
if the underlying context is configured to create proxies and the entity type meets the requirements for creating a proxy.
I have a user entity that contains a collection of survey entities. i would like the assocation to include a filter on the relationship, such as 'IsCompleted', so whenever i eager load (or lazy load for that matter) the collection, this filtering happens.
Is this something we have control over?
thanks!
If you are using a DB back-end that supports views, you might consider using the view as the source for the collection of survey entities. Leverage the power of the DB to do that filtering for you.
Loading of associations for an entity always just gets them all, whether because you used Include during the initial query, called Load after the fact, or lazy-loading caused it. The concept of the navigation property kind of assumes this behavior.
E.J. Brennan's answer would work well. If you're not concerned about loading all surveys behind the scenes (because of performance/memory reasons or something) then you might also consider creating a separate property via a partial class definition on your entity that returns the filtered list.
public partial class User
{
public ICollection<Survey> CompletedSurveys
{
get { return Surveys.Where(s => s.IsCompleted); }
}
}
There is an Entity with many relationships, when i say to EF load a query on a Entity, it loads all properties(OK) with relationships(i don't want)!
This is a big penalty on performance, because i just need some properties not All relationships.
How to say EF that just load entity's property and Don't load relationships (EntityCollection<TEnitity>) ?
I want load relationships's properties by hand!
Are you sure the navigation properties are being eagerly loaded? They shouldn't be by default. Are you using POCO or Code First? If you are, then you need to make sure your navigation properties are marked "virtual". Virtual properties will be lazy loaded.
To check whether navigation properties are lazy loading or eager loading, you'll want to use a tool like SQL Profiler.
JohnnyO is correct; The default value for ObjectContextOptions.LazyLoadingEnabled is false. However, when I create a model from the database, the default value for the model is true. If you are using the generated EF classes, try setting this to false.
Why are the entity class methods declared as public virtual, when the class is to be mapped with a table using NHibernate.
Is the answer that NHibernate will be able to override these methods at runtime?
Yes. NHibernate will return a proxy to your object. In the simplest case, this will be fully uninitialized, and just aware of its type and id. Thus NHibernate will need to intercept method calls on the object and initialize it before the body of the message is called.
NHibernate requires this by default because it generates a proxy for your class, to support lazy loading of the entity (not to be confused with lazy loading of associated entities or collections).
When loading an entity from the DB using NHibernate's 'ISession.Load' method, NHibernate will return a proxy for that entity, which means that it returns an empty entity, where only the primary key (identifier) is set. The values of the other properties are only retrieved once you actually read a property.
However, you can disable this behaviour. In your NHibernate mapping, you can specify that no dynamic proxies should be used by NHibernate for an entity. This is fairly simple to do, you just have to specify lazy="false" on the class - mapping:
MyEntity.hbm.xml:
<class name="MyEntity" table="MyTable" lazy="false">
</class>
By doing this, you do not have to declare virtual properties or methods.
I mostly do it this way, since I don't wan't to declare properties or methods as virtual, if my domain model doesn't require this. I can live with the -imho- minimal performance hit of not using dynamic proxies.
NHibernate needs properties to be virtual in order to support lazy-loading via proxy classes.