Do I have to set foreign key properties manually when I change associations? - entity-framework

I'm migrating from Linq-to-SQL to Entity Framework (4.4), using Database First with a DbContext. I'm wondering whether the following behavior is normal:
using (var e = new AgendaEntities()) {
var store = e.Stores.First();
var office = e.Offices.Create();
office.Store = store; // Set association
Console.WriteLine(office.StoreID); // shows Guid.Empty, expected store.ID!
}
In L2S, setting the Store association to an entity would also update the StoreID key. In EF, this doesn't seem to be happening. This is regardless of whether the entities are new or loaded from the context.
When I SaveChanges, it saves correctly and the StoreID is updated to match office.ID, but why does this only happen after the save?
Is there something I'm missing, or am I now supposed to keep foreign keys in sync manually?
Solution Edit:
This is called property fixup, and used to be done automatically by the generated proxies. However, with DbContext this is no longer the case. According to this Connect issue, this is by design.
Hello,
The DbContext template actually doesn't generate classes that will be used as change tracking proxies - just lazy loading proxies (which don't do fix-up). We made this decision because change tracking proxies are complex and have a lot of nuances that can be very confusing to developers.
If you want fix-up to occur before SaveChanges you can call myContext.ChangeTracker.DetectChanges.
~EF Team
An alternative is to call DbContext.Entry(entity), which will sync up the entity. This is described in this article: Relationships and Navigation Properties under "Synchronizing the changes between the FKs and Navigation properties"

No. Entity framework does this for you. Read Relationships and Navigation Properties for more information.
By assigning a new object to a navigation property. The following
code creates a relationship between a course and a department.
If the objects are attached to the context, the course is also
added to the department.Courses collection, and the
corresponding foreign key property on the course object is set to the
key property value of the department.
course.Department = department;
But as you observed, this only happens after you call SaveChanges or one of the other actions mentioned in the "Synchronizing the changes between the FKs and Navigation properties" portion of the document linked above.
If you are using POCO entities without proxies, you must make sure
that the DetectChanges method is called to synchronize the related
objects in the context. Note, that the following APIs automatically
trigger a DetectChanges call.
DbSet.Add
DbSet.Find
DbSet.Remove
DbSet.Local
DbContext.SaveChanges
DbSet.Attach
DbContext.GetValidationErrors
DbContext.Entry
DbChangeTracker.Entries
Executing a LINQ query against a DbSet
If this is not happening at all, my guess is that you haven't properly defined StoreID as the foreign key of the navigation property Store.

Related

Does Entity Framework Core have a simple way of preventing the update of child or parent entities?

I'm trying to write an UpdateStatus method which will only update the Status field of an entity when I save changes to the database. If any other fields in the entity have changed I don't want to save those changes to the database. That is simple enough for the entity's own fields, using:
using (var context = new DataAccessContext())
{
context.Attach(entity);
context.Entry(entity).Property(e => e.StatusCode).IsModified = true;
context.SaveChanges();
}
However, I've discovered that any related entity reachable via a navigation property of the entity I'm setting the status of will be inserted if that related entity does not have a key value set. So if a new Child entity is added to entity.Children by some calling code, and the Child entity ChildId property is 0, that Child will be inserted into the database.
Is there any easy way in EF Core to avoid inserting related entities?
I've found an old StackOverflow post that shows how to do it in the pre-Core Entity Framework: How do I stop Entity Framework from trying to save/insert child objects? However, that answer involves looping over every related entity. Is there an easier way in EF Core?
The reason I'm looking for an easier way is that my hierarchy of entities is 5 layers deep. And I've found that it's not enough to detach just the immediate children of an entity. You have to use nested loops to detach the grandchildren, the great-grandchildren, etc. If you only detach the immediate children they won't be inserted but EF Core will attempt to insert new grandchildren and will crash and burn because it hasn't inserted their parents. It gets pretty messy.
I could just read a fresh copy of an entity from the database before updating its Status but I'm trying to avoid having to do a read before I write.
What you are asking is quite simple in EF Core. If you don't want EF Core change tracker operation to process the related data, set the EntityEntry.State rather than calling DbContext / DbSet methods like Attach, Add, Update, Remove etc.
This behavior is different from EF6 where methods and setting state are doing one and the same, and is partially mentioned in the Saving Related Data - Adding a graph of new entities
documentation topic:
Tip
Use the EntityEntry.State property to set the state of just a single entity. For example, context.Entry(blog).State = EntityState.Modified.
So in your sample, simply replace
context.Attach(entity);
with
context.Entry(entity).State = EntityState.Unchanged;
Entity Framework Core ignores relationships unless you explicitly
include them in queries.
When attaching an entity to the database that has related data/ child properties, those entities will be included in the query.
So to fix this issue all you need to do is set those child properties to null and then EF Core will ignore the child-objects when you're updating the parent-object.

What is the overhead of Entity Framework tracking?

I've just been talking with a colleague about Entity Framework change tracking. We eventually figured out that my context interface should have
IDBSet<MyPoco> MyThings { get; }
rather than
IQueryable<MyPoco> MyThings { get; }
and that my POCO should also have all it's properties as virtual.
Using the debugger we could then see the tracking objects and also that the results contained proxies to my actual POCOs.
If I don't have my POCO properties as virtual and have my context interface using IQueryable<> instead of IDbSet<> I don't get any of that.
In this instance I am only querying the database, but in the future will want to update the database via Entity Framework.
So, to make my life easier in the future when I come to look at this code as a reference, is there any performance penalty in having the tracking info/proxies there when I will never make use of them?
There is a performance penalty of tacking entities in EF. When you query using entity framework EF will keep a copy of values loaded from database. Also single Context instance keeps track of only single instance of an entity. So EF has to check whether it already has a copy of the entity before it creates an instance(ie. There will be lot of comparisons going behind the scenes).
So avoid it if you don't need it. You can do so as follows.
IQueryable<MyPoco> MyThings { get { return db.MyThings.AsNoTracking(); } }
MSDN page on Stages of Query Execution details the cost associated with each step of query execution.
Edit:
You should not expose IDBSet<MyPoco> MyThings because that tells the consumer of your API that your entities can be added, updated and deleted when in fact you intend to query the data.
Navigation properties in the model classes as declared as virtual so as to imply lazy load feature which means the navigation property will only be needed if required. As far as the Entity objects are concerned, there main aim is to load the specific table records from the database into the DbSet which comes from DbContext. You can't use IQueryable in this case. Also, it doesn't make any sense with the DataContext. IQueryable is an altogether different interface

how can i know when a self-tracking entity has been changed?

I have been working with the Entity Framework + Self-Tracking entities, and came out with a problem:
Is there any way to determine when an entity has been changed??
For example: If you have an entity User with two fields: Name and Password, you can know if an User instance has been changed making:
<user>.ChangeTracker.State != ObjectState.Unchanged;
My problem is when the User has a Person, and the person has a field Email. I want that if the email field is changed, then the corresponding User is changed too.
I have been trying with methods such as: <user>.StartTrackingAll(); but this does not work with navigation properties (or maybe i am doing something wrong). Some help about this can be found here.
Remember that the Self tracking entities are autogenerated via T4 templates, so the clases can't be modified.
First when wanting to know if any entity in a so-called object graph has changed you can recurse through all entities contained in trackable collections or one-to-one navigation properties of a root entity (user in your case). This way you can know if a person inside the root entity has changed. This is actually how I check complex object graphs for any changes in any of the contained entities. But also for checking out if any of these entities have critical validation errors (so the user can't persist them yet).
Remember that the Self tracking entities are autogenerated via T4 templates, so the clases can't be modified.
Not true. First of all you can modify the T4 template to generate more (complex) code to achieve the things you want. And second, it generates partial classes which can easily be extended with custom (non-generated) code.
If you change the email in the Person instance only that instance is correctly marked as modified. That is absolutely correct behaviour. What do you expect? Do you expect that change to property in related entity will propagate changed state to relations? That would make STEs completely useless because any single change to entity graph would make all entities in the graph modified and each this modification causes additional roundtrip to the database.
If you want to set User as modified when you are changing email simply create some method or handle some event and call person.User.MarkAsModified()

Entity Framework Service Layer Update POCO

I am using the Service Layer --> Repository --> Entity Framework (Code-First) w/POCO objects approach, and I am having a hard time with updating entities.
I am using AutoMapper to map my Domain Objects to my View Models and that works good for getting the data, no how do I get that changes back into the database?
Using pure POCO objects, I would assume that there is no sort of change tracking, so I see my only option is to handle it myself. Do you just make sure that your View Models have the EXACT same properties as your Domain Objects? What if I just change a field or two on the View Model? Won't the rest of the fields on the Domain Object get overwritten in the database with default values?
With that said, what is the best approach?
Thanks!
Edit
So what I am stumbling on is this, lets take for example a simple Customer:
1) The Controller has a service, CustomerService, that calls the services GetCustmoerByID method.
2) The Service calls into the CustomerRepository and retrieves the Customer object.
3) Controller uses AutoMapper to map the Customer to the ViewModel.
4) Controller hands the model to the View. Everything is great!
Now in the view you do some modifications of the customer and post it back to the controller to persist the changes to the database.
I would assume at this point the object is detached. So should the model have the EXACT same properties as the Customer object? And do you have to make hidden fields for each item that you do not want to show, so they can persist back?
How do you handle saving the object back to the database? What happens if your view/model only deals with a couple of the fields on the object?
If you're using EF Code First, i.e: the DbContext API, then you still do have change tracking which is taken care of by your context class.
after making changes to your objects, all you have to do is call SaveChanges() on your context and that will persist the changes to your database.
EDIT:
Since you are creating a "copy" of the entity using AutoMapper, then it's no longer attached to your context.
I guess what you could do is something similar to what you would in ASP.NET MVC (with UpdateModel). You can get the original entity from your context, take your ViewModel (which may contain changed properties) and update the old entity, either manually (just modified properties), or using AutoMapper. And then persist the changes using context.SaveChanges().
Another solution would be to send the model entity as [part of] the ViewModel. This way, you'll have your entity attached to the container and change tracking will still work.
Hope this helps :)
You are absolutely right that with a detached object you are responsible for informing the context about changes in your detached entity.
The basic approach is just set the entity as modified. This works for scalar and complex properties but it doesn't work for navigation properties (except FK relations) - for further reading about problems with navigation properties check this answer (it is related to EFv4 and ObjectContext API but same problems are with DbContext API). The disadvantage of this approach is that all fields in DB will be modified. If you just want to modify single field you still have to correctly fill others or your database record will be corrupted.
There is a way to explicitly define which fields have changed. You will set the modified state per property instead of whole entity. It is little bit harder to solve this on generic approach but I tried to show some way for EFv4 and for EFv4.1.
I agree with #AbdouMoumen that it's much simpler to use the model entities at the view level. The service layer should provide an API to persist those entities in the data store (db). The service layer shouldn't dumbly duplicate the repository lawyer (ie: Save(entity) for every entity) but rather provide a high level save for an aggregate of entities. For instance, you could have a Save(order) in the service layer which results in updating more basic entities like inventory, customer, account.

Inheritance problems with Entity Framework (table per type)

For part of the project I'm currently working on, I have a set of four tables for syndicatable actions. One table is the abstract base for the other three, and each table is represented in my EF model like so:
EF Model -- Actions http://chris.charabaruk.com/system/files/images/EF+Model+Actions.png
There are two problems that I'm currently facing with this, however. The first problem is that Actor (a reference to a User) and Subject (a reference to an entity of the class associated with each type of action) are null in my subclasses, despite the associated database columns holding valid keys to rows in their associated tables. While I can get the keys via ActorReference and SubjectReference this of course requires setting up a new EF context and querying it for the referenced objects (as FooReference.Value is also null).
The second problem is that the reciprocal end of the relationship between the concrete action classes and their related entity classes always turn up nothing. For example, Task.RelatedActions, which should give me all TaskAction objects where Subject refers to the particular task object on which RelatedActions is called, is entirely devoid of objects. Again, valid rows exist in the database, Entity Framework just isn't putting them in objects and handing them to me.
Anyone know what it is I'm doing wrong, and what I should do to make it work?
Update: Seems that none of the relationship properties are working in my entity model any more, at all. WTF...
I think the issue you are experiencing here is that by default the EF does not automatically load related entities. If you load an entity, the collection or reference to related entities will be empty unless you do one of the following things:
1) Use eager loading in order to retrieve your main entity and your related entity in a single query. To do this, modify your query by adding a call to the Include method. In your sample above, you might use the following query:
from a in context.Actions.Include("Actor") select a
This would retrieve each of the actions with the related Actor method.
2) Use explicit lazy loading to retrieve the related entity when you need it:
action1.ActorReference.Load()
In the version of the EF which will ship with .Net 4.0, you will also have the following additional option:
3) Turn on implicit lazy loading so that related entities will automatically be retrieved when you reference the navigation property.
Danny