EF 4.3.1 How adding affects related entities that exist already - entity-framework

Imagine this graph:
Device 1..* OperatingEnvironment 1..* NetworkEndpoint
If I construct a detached entity graph in-memory and the Device at the root of the graph is new while the OperatingEnvironment exists and the NetworkEndpoint exists but is assigned to a different OperatingEnvironment, will EF figure all this out?
When I say 'figure this out', its simply a case of walking the graph and doing (IfExist ? MergeValues : AddNew) Because the entities all have foreign keys, relationships should effectively get reassigned automatically during the property merge.
Is this how EF works or will I have to walk my own graph and apply this logic? If I do this, then my in-memory graph will have to be weakly linked, i.e. avoid linking via navigation properties and instead use the foreign key values, otherwise the whole graph will be added as as soon as I add one entity since EF will crawl the navigation properties.
Thanks - hope that's clear as mud.

You must do it yourselves. EF has no internal logic to detect if the entity exists in the database or not.

Related

Entity Framework Model first: adding an association without creating foreign key properties?

I'm playing with the Entity Framework model designer, and I've got a question about creating entity associations:
In the "create association" dialog, when I create a 1:many association, it offers this checkbox:
"Add foreign key properties to the [entityname] entity"
I've been checking this box and I get results that are expected and make sense to me: Clicking the navigation property in the diagram highlights the related field in both entities that tie them together.
But, what would it mean not to check this box? I've tried this, and I then see no place in the entity to store a reference to the parent table's primary id. Am I correct that the navigation properties don't store any data in the database? If so, how could this work? Am I, perhaps, expected to manually map the navigation property to an Int32 field on the entity?
Associations represent relationship between entities. In the database (relational model) these relations are modeled by using foreign keys and - in the case of many-to-many - a join table. In the object model relations are typically modeled as references to the related object (in EF they are often referred to as Navigation Properties). The problem arises when you need to create or modify a relationship in the object model - you always need to have a reference of the related object you would like to set. In a pure object model this usually is not a problem but in case of ORM it means that if you don't have the related entity you need to send a query to the database to get the object to be able to set the reference to. However oftentimes - even if you don't have the related entity - you know the Id of the related entity. So, if the foreign key properties were exposed (and handled) in your object model you could create or modify a relationship without having to send additional queries to the database. This is what the checkbox is about. If you check it your entities will have (extraneous from object model perspective) properties mapped to foreign key columns in the database which you can use to manipulate relationships.

Entity Framework - updating a large graph of entities

I have a large "graph" of entities that I work with in a disconnected fashion. They are POCO entities, implementing my own simple change tracking flags (IsNew, IsChanged, IsDeleted). When the time comes to save changes, I pass the entire graph back to the business tier, which does the following:-
context.Batches.Attach(batch);
where batch is the entity at the very top of the graph hierarchy. This has a "cascading effect" and attaches all entities in the graph, which all end up in an unchanged state. I then walk through the hierarchy setting each entity's state via the ObjectStateManager, based on the values of my change tracking flags.
The problem with this approach is that new entities need to be assigned unique IDs (despite being "identity" columns). I can't just leave them all as 0 otherwise the Attach fails with the message "An object with the same key already exists...".
Having to assign temporary, unique IDs is starting to get a bit messy, and I wondered if there was a better solution. I wondered if I could walk the graph and do an Attach or an Add one entity at a time (based on my change tracking flags), but this doesn't seem to be possible, as both methods "cascade", resulting in all child entities getting added or attached too. Is there any way around this?
I'm using EF5, ObjectContext template, if that makes a difference.
It would be much easier to first fetch the current entity graph from the context (with Change Tracking and Proxy Generation enabled), then walk each node and update/delete/add data based on the detached graph (using your own internal persistence status field).

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

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.

RIA services presentation model with 1-many or many-many relationships

I'm trying to get a presentation model (discussed here and here) working in RIA. All the examples I can find are simple, flat data entities with no 1-many or many-many relationships, which are what I can't get working - specifically, on updates and inserts into associative relationships.
Queries I can get working fine - I have my presentation classes marked up with Association attributes (and Include attributes, where appropriate), and I have a good understanding about how data is loaded into the client side and maintained there as entities. I also have inserts of new entities covered. However, I'm experiencing the following problems. For the following examples, assume we have simple Album and Artist entities, where an Album has a single artist and an Artist can have zero to many albums. Both have a Name property.
On the client side, if I do myArtist.Albums.Add(anAlbum) or myArtist.Albums.Remove(anAlbum), nothing happens. HasChanges returns false. (Note that myArtist and anAlbum were obtained solely in code by loading the entities and iterating to get references to specific entities: I'm not doing anything in UI or with DomainDataSources yet, just dinking around).
If I update the Name on an Artist and SubmitChanges, when the Update method gets called on the server, the Albums collection is null.
Does anyone have any suggestions, or can you point me to an example that uses more complex objects?
EDIT (keeping the above for posterity): Alright, it appears that the second issue (a reference to an entity or a collection of entities showing as null when Update gets called on the server) exists because the child entites aren't marked as Changed and so they aren't being serialized and sent back. I know you can force that to happen by using [Composition] and I have gotten it to work that way, but this is not a compositional relationship and I want both entities to be "top-level" entities. How can I mark an entity as changed?
The problem was that my [Association] attributes weren't correctly defined. I didn't realize that the association's Name property has to be the same on both sides of the association. When the names are the same and you do a build, the generated code on the client uses a different constructor for the EntityCollection used by the "parent" to refer to the "children" than it does if the associations aren't set up right. The new constructor takes callbacks that do a little bit of extra handling when you call Add and Remove on the collection - specifically, they take the child entity you are adding or removing and modify the property on it that refers to its parent so that everything remains in sync: the collection you removed the object from, the collection you added it to, and the object's reference to its parent.

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