Note that there are some explanatory texts on larger screens.

plurals
  1. POEntity Framework Code First - Adding 1:many through aggregate root
    primarykey
    data
    text
    <p>I have a question regarding adding children to a root entity in Entity Framework 4.1 CF. </p> <p>Considering the following infrastructure Entity base class and two POCOs: </p> <pre><code>public abstract class EntityBase&lt;TKeyDataType&gt; { [Key] public TKeyDataType Id { get; set; } // Equality methods ommitted for brevity... } public class Foo : EntityBase&lt;int&gt;, IAggregateRoot { public string Foo1 { get; set; } public virtual ICollection&lt;FooSibling&gt; Siblings { get; set; } } public class FooSibling : EntityBase&lt;int&gt; { public string SiblingPropFoo { get; set; } public int FooId { get; set; } public Foo Foo { get; set; } } </code></pre> <p>Notice that <code>Foo</code> implements <code>IAggregateRoot</code> (just an empty interface - think of it as metadata in the "data about data" context). </p> <p>So far, so good. If I run this, EF creates the database with the appropriate 1:many relationship.</p> <p>The only fluent mapping I have on these two entities are: </p> <pre><code>modelBuilder.Entity&lt;Foo&gt;() .HasMany(x =&gt; x.Siblings) .WithRequired(x=&gt;x.Foo) .WillCascadeOnDelete(true); </code></pre> <p>No <code>FooSibling</code> without a <code>Foo</code>. Blow away a <code>Foo</code>, you blow away all its sibling. This piece works.</p> <p>The issue is when adding FooSiblings POCO to the Foo POCO, I have to use unique negative numbers as shown in this service method:</p> <pre><code>public ResponseBase UpdateBy(RequestBase&lt;Foo&gt; request) { ResponseBase response = new ResponseBase(); try { Foo foo = FooRepository.FirstOrDefault(x =&gt; x.Id == request.Entity.Id); // Dummy adds to test associations. // These come back on the Foo inside the request, but I'm explicitly putting them here // for the purpose of this question. request.Entity.Siblings.Add(new FooSibling() { Id = -2, SiblingPropFoo = "Prop1", SiblingPropFoo2 = "Prop2" }); request.Entity.Siblings.Add(new FooSibling() { Id = -1, SiblingPropFoo = "Prop1", SiblingPropFoo2 = "Prop2" }); // Update Foo's scalars and children (mapping is Foo-&gt;Foo) foo = AutoMapper.Mapper.Map(request.Entity, foo); UnitOfWork.Commit(); response.Success = true; } catch (Exception e) { response.Success = false; response.Message = e.Message; } return response; } </code></pre> <p>Once the <code>UnitofWork.Commit()</code> is called (it just calls <code>SaveChanges</code> of the context - no magic here), all is well... </p> <p>However, if I don't use unique negative numbers like and just try to set its parent, like this: </p> <pre><code>request.Entity.Siblings.Add(new FooSibling() { Foo = foo, SiblingPropFoo = "Prop1", SiblingPropFoo2 = "Prop2" }); request.Entity.Siblings.Add(new FooSibling() { Foo = foo, SiblingPropFoo = "Prop1", SiblingPropFoo2 = "Prop2" }); </code></pre> <p>Only one gets persisted to the database. </p> <p>The only other way I know of to do it without using negative numbers is to use the FooSiblings DbSet directly in the service method: </p> <pre><code>IRepository&lt;FooSibling&gt; siblingRepo = new CookieCutterEntityFrameworkRepository&lt;FooSibling&gt;(UnitOfWork); siblingRepo.Insert(new FooSibling() { FooId = foo, .... }); </code></pre> <p>My CookieCutter repository is abstracting all the DbSet stuff, etc.</p> <p>But ... stripping off all the abstraction and generic voodoo for clarity, the question really comes down to is there a way to update my Foo POCO (the root Entity) and add new siblings through one DbSet without using negative numbers? </p> <p>For reference (without abstraction using pure DbContext): </p> <pre><code>// This works (using multiple DbSets/Repositories always make life easier...) Ctx.Foos.Update(foo); Ctx.FooSiblings.Add(new FooSibling() { Foo = foo, ... }); Ctx.FooSiblings.Add(new FooSibling() { Foo = foo, ... }); Ctx.SaveChanges(); // This works too (using negative number trick - foo scalar properties get // updated and the siblings get persisted to the database properly). foo.Siblings.Add(new FooSibling() { Id = -2, ....}); foo.Siblings.Add(new FooSibling() { Id = -1, ....}); Ctx.Foos.Update(foo); Ctx.SaveChanges(); // This doesn't work (but it's what I'm striving for to drive everything off the root). foo.Siblings.Add(new FooSibling() { Foo = foo }); foo.Siblings.Add(new FooSibling() { Foo = foo }); Ctx.Foos.Update(foo); Ctx.SaveChanges(); </code></pre> <p>In the last case (the non-working case), I'm striving to configure it in a fashion where it picks up any changes to the Foo POCO itself. </p> <p>I've tried with Proxies turned off and on. Also, in the way this is setup, the context remains in scope for the life of the entire HTTP request. </p> <p>If not possible, what suggestion(s) would you give? </p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload