【问题标题】:Entity Framework Code First - Adding 1:many through aggregate root实体框架代码优先 - 通过聚合根添加 1:many
【发布时间】:2011-10-09 14:00:36
【问题描述】:

我有一个关于在 Entity Framework 4.1 CF 中将子级添加到根实体的问题。

考虑以下基础设施Entity基类和两个POCO:

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:many 关系的数据库。

我对这两个实体的唯一流畅映射是:

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

没有Foo 就没有FooSibling。吹走Foo,你吹走它所有的兄弟姐妹。这件作品有效。

问题是在将 FooSiblings POCO 添加到 Foo 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, .... });

我的 CookieCutter 存储库正在抽象所有 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 请求的生命周期内保持不变。

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

【问题讨论】:

    标签: .net entity-framework-4 domain-driven-design ef-code-first poco


    【解决方案1】:

    如果我没看错,问题应该是通过 dbcontext 或 objectcontext。

    首先我想看看你的最后一组例子......没有抽象。当您将图表附加到上下文时,图表中的所有内容都附加为未更改。时期。在上下文对它们有任何了解之前,上下文并不关心您如何将“孩子”添加或附加到根(例如,兄弟姐妹到 foo)。如果 foo 已经被上下文知道然后你添加,那么上下文知道你是如何进行链接的..你说“添加”所以它将它们标记为已添加并且它们将被插入。即使根是不是新的。您必须将其状态更改为“未更改”。但是在您的情况下,您正在获取一个断开连接的图表并将其附加,因此图表中的所有内容都被视为未更改。您必须将每个同级的状态显式更改为您希望 SaveChanges 注意到它需要插入的状态。

    现在到您的存储库。我不知道 wtf 是负数。 :) 而且我没有时间进行试验。 (很好奇这是如何欺骗 savechanges 的,但这是一个臭名昭著的 hack :))这取决于您的 FooRepository 查询背后发生了什么。如果返回的 foo 被上下文跟踪,那么我会期望当你添加兄弟姐妹时,上下文会知道它们被添加并会创建一个插入。但是如果它没有被跟踪,那么当你添加兄弟姐妹时,上下文就不会知道“添加”。无论您何时将图形(foo + 其兄弟姐妹)重新附加到上下文,它们都将“未更改”,因此您不会获得所需的插入。

    这完全取决于你的存储库中发生的任何其他事情以及自动映射器的影响(如果有的话)。我猜你在上下文知道图表之前已经完成了所有的工作,所以最后,我认为你正在调用 ATTACH,这将导致没有 INSERTS 被发送到数据库。

    【讨论】:

    • 感谢朱莉的反馈。问题实际上出在我的 EntityBase 对象上。我覆盖了 GetHashCode 方法,并在 ID 本身上返回了 HashCode ......所以 0 的 Hashcode 总是相等的。一旦我将其注释掉,一切都将通过根一起触发。我同意 100% 的负数有点骇人听闻。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-20
    • 2016-10-17
    • 2012-02-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多