0

我有一个关于将实体框架4.1 CF中的子实体添加到根实体的问题。实体框架代码优先 - 通过聚合根添加1:很多

考虑下面的基础设施实体基类和两个波苏斯:

public abstract class EntityBase<TKeyDataType> 
{ 
    [Key] 
    public TKeyDataType Id { get; set; } 

    // Equality methods ommitted for brevity... 
} 

public class Foo : EntityBase<int>, IAggregateRoot 
{ 
    public string Foo1 { get; set; } 

    public virtual ICollection<FooSibling> Siblings { get; set; } 
} 

public class FooSibling : EntityBase<int> 
{ 
    public string SiblingPropFoo { get; set; } 

    public int FooId { get; set; } 
    public Foo Foo { get; set; } 
} 

注意Foo工具IAggregateRoot(只是一个空洞的接口 - 把它作为元数据的上下文中的“关于数据的数据”)。

到目前为止,这么好。如果我运行它,EF使用适当的1:多关系创建数据库。

唯一的一口流利的映射我有两个实体:

modelBuilder.Entity<Foo>() 
      .HasMany(x => x.Siblings) 
      .WithRequired(x=>x.Foo) 
      .WillCascadeOnDelete(true); 

没有FooSibling没有Foo。吹掉一个Foo,你吹走所有的兄弟姐妹。这件作品。

的问题是增加FooSiblings POCO到富POCO的时候,我都用独特的负数如本服务的方法:

public ResponseBase UpdateBy(RequestBase<Foo> request) 
{ 
    ResponseBase response = new ResponseBase(); 
    try 
    { 
     Foo foo = FooRepository.FirstOrDefault(x => 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->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; 
} 

一旦UnitofWork.Commit()被称为(它只是调用上下文的SaveChanges - 这里没有魔法),一切都很好...

但是,如果我不使用独特的负数一样,只是尝试设置其母公司,像这样:

request.Entity.Siblings.Add(new FooSibling() { Foo = foo, SiblingPropFoo = "Prop1", SiblingPropFoo2 = "Prop2" }); 
request.Entity.Siblings.Add(new FooSibling() { Foo = foo, SiblingPropFoo = "Prop1", SiblingPropFoo2 = "Prop2" }); 

只有一个持久化到数据库。

我知道做到这一点,而无需使用负数唯一的另一种方法是直接在服务方法使用FooSiblings DbSet:

IRepository<FooSibling> siblingRepo = new CookieCutterEntityFrameworkRepository<FooSibling>(UnitOfWork); 
siblingRepo.Insert(new FooSibling() { FooId = foo, .... }); 

我18.11存储库抽象所有DbSet东西,等

但是......为了清晰起见,剥离所有抽象和泛型伏都,问题真的归结为是否有方法更新我的Foo POCO(根实体)并通过一个DbSet添加新的兄弟而不使用负数? (使用纯的DbContext没有抽象)

参考:

// 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(); 

在最后一种情况下(非工作情况下),我努力将其配置在它拿起任何变化的时尚Foo POCO本身。

我试过关闭代理服务器。而且,按照这种设置方式,上下文仍然处于整个HTTP请求生命周期的范围内。

如果不可能,您会提出什么建议?

回答

2

如果我正确地阅读这个问题,可以通过dbcontext或objectcontext预期问题。

FIrst我想看看你的最后一组例子..没有抽象。将图形附加到上下文时,图形中的所有内容都将附加为“未更改”。期。上下文并不关心在上下文有任何知识的情况下,如何在根上添加或附加“子”(例如,兄弟姐妹)。如果foo已经被上下文所知,然后你添加,那么上下文知道你如何做链接..你说“ADD”,所以它将它们标记为Added,并且它们将被插入。即使根目录是不是新的。您必须将其状态更改为“未更改”。但在你的情况下,你正在采取一个不连贯的图并附加它,所以图中的每一个都被认为是不变的。您必须明确将每个同级的状态更改为SaveChanges需要注意的事项。

现在到您的存储库。我不知道wtf是与负数。 :)我没有时间去实验。 (好奇的是如何欺骗savechanges,但它是一个臭ha :))这取决于你的FooRepository查询背后发生了什么。如果返回的foo被上下文跟踪,那么我会期望,当你添加兄弟,上下文将知道他们被添加并将创建一个插入。但是如果没有被跟踪,那么当你添加兄弟姐妹时,上下文不会知道“ADD”。在任何时候你将图形(foo +它的兄弟姐妹)重新连接到一个上下文中,它们都将会“无变化”,所以你没有得到想要的插入。

这是所有依赖于GUESS在你的仓库中正在进行的任何其他操作,以及影响automapper的影响(如果有的话)。我猜测你在上下文知道图表之前正在做所有的owrk,所以最后,我认为你正在调用ATTACH,这会导致没有INSERTS被发送到数据库。

+0

感谢您的反馈朱莉。问题实际上是在我的EntityBase对象上。我覆盖了GetHashCode方法,并在ID本身上返回HashCode ...所以0的Hashcode总是相等的。一旦我评论说,一切都是通过根源共同发射的。我同意100%负面的数字有点骇人听闻。 – Forest

+0

ahhhhhh ....好抓! :) –