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.
Related
I'm using Entity Framework. I've attached a POCO object representing an entity in the DB to my dbcontext using:
var entity = new MyEntity() { ID = 1, AnotherItemID = 10 };
context.Set<T>().Attach(entity);
So far so good. I can access the set and work with the entity I've added. It's added in the Unchanged state. However, it is only a POCO and not a Proxy. Therefore, when I try to access a navigation property, e.g. myEntity.AnotherItem, I just get a null back.
Does anyone know if there is a way to have EF resolve navigation properties for POCO classes attached in this way? Or of a way to cast the POCO to a proxy class?
Thanks
Update
There are two ways to solve this (of course there may be others too!). One is the Explicit Loading option in the answer below. The other way, which allows lazy loading to work, is to use the DBSet Create method rather than the POCO new keyword when creating entities to be attached. More info about that here:
EF4.3 Code-First, MVC, Lazy Loading After Attaching in POST Action
You can use Explicity Loading:
//When you want to load a reference navigation property
context.Entry(entity).Reference(p => p.AnotherItem).Load();
//When you want to load a collection navigation property
context.Entry(post).Collection(p => p.Items).Load();
I have 3 tables: Courses, Departments, and Universities.
When I pull the information from the database (using entity framework), I am attempting to map, for example, a Course to a CourseDTO. I am trying to set it up in such a way that the CourseDTO automatically checks if the relationships exist (is not null), then hook up the relationship in the DTO.
Problem is once I run:
db.Courses.Include(c=>c.Department).Include(c=>c.University)
It maps every nested permutation of these relationships, so my automatic mapping to the DTO just creates a stackoverflow because it goes on forever. (eg. Course maps the Department which maps the Courses in that Department, which maps the Department, etc.)
What is the best solution to avoid this problem?
I would suggest turning off Lazy Loading for EntityFramework via
context.Configuration.LazyLoadingEnabled = false
This will prevent the sub-objects that you did not explicitly include from being expanded by Entity Framework when they are accessed.
Either that or create a custom mapping method to include only the objects you want in your DTO.
In short, why does this fail (myChildObject is not added to the database). Note that it works with ObjectContext:
using (var db = new dbEntities())
{
var myParentObject = db.parentObjects.First(); // this definitely exists in the db
// this **should** attach myChildObject to the context,
// and therefore add it to the db on .SaveChanges() - it doesn't!
var myChildObject = new childObject(){
parentObject = myParentObject
};
db.SaveChanges();
}
This MSDN Blog Post says
You can add a new entity to the context by hooking it up to another entity that is already being tracked. This could be by adding the new entity to the collection navigation property of another entity or by setting a reference navigation property of another entity to point to the new entity.
Surely the above code should work because myChildObject references myParentObject which is a tracked object. EF should be smart enough to figure out that it needs adding into the childObjects collection. It worked fine when I was using ObjectContext and now I'm finding that I need to rewrite all of my code to get it to work with dbContext.
To get it to work I have to rewrite it like this:
using (var db = new dbEntities())
{
var myParentObject = db.parentObjects.First(); // this definitely exists in the db
var myChildObject = new childObject();
myParentObject.childObjects.Add(myChildObject);
db.SaveChanges();
}
If you were using POCO entities with ObjectContext it worked indeed. But not because EF's change tracking worked differently than with DbContext but because the POCO entities generated by the EF 4 T4 templates contained "relationship fixup" methods.
Basically the property setter for the line parentObject = myParentObject wasn't only an object assignment but the setter included a call to a method that in the end exactly did what you are doing manually now, namely: myParentObject.childObjects.Add(myChildObject). At this point the rule "You can add a new entity to the context by hooking it up to another entity that is already being tracked" applies and myChildObject gets added to the context and inserted into the database.
For the T4 templates that generate POCO entities for DbContext those fixup methods have been removed because they were causing trouble in other scenarios. Especially when lazy loading is involved your reference assignment and the automatic call of myParentObject.childObjects... in the property setter would trigger lazy loading on the collection and load all childObjects first that are already stored for myParentObject before the new child is added to the collection. If those are thousands this is a huge unnecessary overhead, performance gets disastrous and the reason for a suddenly bad performance (just because you assigned a single reference property) isn't easy to detect if you are not aware of the fixup methods that run behind the scenes.
Here and here and here and here are examples about the confusion that relationship fixup methods were causing.
You could modify the T4 templates and add relationship fixup methods again - or if you are using Code-First just write them by hand in your entity classes - to get the old behaviour back. But this might be more complex than and at least as much work as changing your existing code the way you've outlined in your last code snippet - which I would certainly prefer over having those bothersome fixup methods back.
#theyetiman you're doing a little interpretation mistake of the blog text.
see:
[...]
or by setting a reference navigation property of another entity to point to the new entity.
In this part the blog said you can set a reference navigation property of a tracked object with a new entity.
like this:
[tracked entity].NavigationProperty = [new entity];
But you tring to do:
[new entity].Navigation Property = [tracked entity];
This not works. If your childObject was tracked and parentObject not you would be able to add parentObject setting it in childObject property, but the opposite is not true.
Question:
Is it possible when dealing with dynamic proxy to pull out the underlying POCO when we need to serialize them?
Rationale:
I have a requirement to serialize (XML) my POCO entities using EF Code First but quickly found that DbContext creates dynamic proxy for my POCO and that makes it hard to serialize.
I have tried the following:
Disable proxy creation in the DbContext and work only with pure POCO. This allows me to serialize the instances any way I like. The only catch is that navigational properties are not being tracked, therefore, I must attach all related entities manually when I want to save otherwise new entities will always be created (see code example).
Implement ISerializable interface on the POCO to manually handle serialization. This is a lot of work and is not a sustainable solution.
Code example.
// Attach and update tags
foreach (var tag in entity.Tags)
{
Context.Entry(tag).State = Context.Tags.Any(t => t.ID == tag.ID)
? EntityState.Modified
: EntityState.Added;
}
// Attach and update state.
Context.Entry(entity).State = Context.Resources.Any(x => x.ID == entity.ID)
? EntityState.Modified
: EntityState.Added;
As you can imagine, the complexity can get out of hand when my entity have more relationships.
Is it possible when dealing with dynamic proxy to pull out the
underlying POCO when we need to serialize them?
No because there is no underlying POCO - the proxy is not a wrapper around entity instance. It is entity instance directly.
You can use DataContractSerializer and ProxyDataContractResolver to serialize proxied POCOs but serializing proxied entities sounds like you are trying to serialize entities with lazy loading enabled - that can serialize much more than you expect because every property will be lazy loaded recursively until there is no single non-loaded navigation property in the whole object graph.
You must also handle circular references when using DataContractSerializer by marking your entities with [DataContract(IsReference = true)] and every serializable property with [DataMember].
The only catch is that navigational properties are not being tracked
Entities without proxy are tracked as well. The tracking is dependent on entity being attached not entity being proxied.
I must attach all related entities manually when I want to save
You must always attach deserialized entities if you want to persist them.
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.