0

我刚刚开始从代码优先的场景中自学实体框架 (6)。我的问题是我不明白如何正确指示 EF 某些实体可以在其他实体之间共享。

这是一个具有三层树结构的非常简单的场景。类A对象拥有类B对象,类对象拥有或引用类C对象:

public class A
{
    [Key]
    public string Id { get; set; }

    public ICollection<B> Bees { get; set; }

    public override string ToString() { return Id; }
}

public class B
{
    [Key]
    public string Id { get; set; }

    public ICollection<C> Cees { get; set; }

    public override string ToString() { return Id; }
}

public class C
{
    [Key]
    public string Id { get; set; }

    public override string ToString() { return Id; }
}

我现在创建一个场景,其中一个A对象拥有五个B对象,而这五个对象又共享五个C对象的集合。这是我使用的 DbContext:

public class Context : DbContext
{
    public DbSet<A> As { get; set; }

    public DbSet<C> Cs { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // SHOULD I INSTRUCT EF HOW TO HANDLE THIS HERE?
        base.OnModelCreating(modelBuilder);
    }

    public Context(string nameOrConnectionString)
        : base(nameOrConnectionString)
    {
    }
}

这里有一些简单的代码来设置这个场景:

internal class Program
{
    private static void Main(string[] args)
    {
        var context = new Context(@"Data Source=(localdb)\v11.0; Initial Catalog=TestEF6.Collections; Integrated Security=true");
        var sharedCees = createCees("A1.B1", 5, context);
        context.As.Add(new A { Id = "A1", Bees = createBees("A1", 5, sharedCees) });
        context.SaveChanges();
    }

    private static ICollection<B> createBees(string aId, int count, ICollection<C> cees = null)
    {
        var list = new List<B>();
        for (var i = 0; i < count; i++)
        {
            var id = aId + ".B" + (i + 1);
            list.Add(new B { Id = id, Cees = cees ?? createCees(id, count) });
        }
        return list;
    }

    private static ICollection<C> createCees(string bId, int count, Context saveInContext = null)
    {
        var list = new List<C>();
        for (var i = 0; i < count; i++)
        {
            var id = bId + ".C" + (i+1);
            var c = new C {Id = id};
            list.Add(c);
            if (saveInContext != null)
                saveInContext.Cs.Add(c);
        }
        if (saveInContext != null)
            saveInContext.SaveChanges();
        return list;
    }
}

当 EF 创建数据库 ('TestEF6.SharedEntities') 时,它假定A -> B以及B -> C是一对多关系,并且子实体是组件,完全由其主实体拥有和控制。

那么,我如何让 EF “看到” 的实例C可以由 的实例共享B

老实说,我要求快速入门 EF。我确实意识到我可以通过网络来解决这个问题,但如果有人能指出我正确的方向,我将非常感激。

干杯

4

1 回答 1

0

Gert 建议我在C类中添加一个集合属性,从而使我走上正轨。B事实上,这足以让 EF/CF 自动识别和之间的多对多关系C。但是,代码优先的重点是设计类的域模型,然后让 EF 持久化它们,而不必让它们陷入持久性信息的困境。

我对注释Key属性甚至是属性没有任何问题Required。这种信息在领域模型中实际上是有意义的。它们可以被域代码使用,但即使它们不是,它们也会增加代码的清晰度。但是添加除了作为 EF 自动魔法的提示之外没有其他功能的属性似乎不是一个非常优雅的解决方案。

因此,我使用 fluent API 进行了更多试验,并意识到我错过了.WithMany(). 我正在寻找一种通用形式,它可以指定另一种类型的多对多关系。在我的脑海中,我会写:modelBuilder.Entity<B>.HasMany(b => b.Cees).WithMany<B>()。事实证明,无参数重载 的WithMany()服务于这个确切的目的,因为C这种情况下的类型已经由第一HasMany()部分指定。

B因此,总而言之,EF 将识别类和之间的多对多关系C,而无需C使用额外的通用类型B项集合“乱扔”类。所以,这就是我们如何描述两个类之间的多对多关系,而无需触及领域类:

public class Context : DbContext
{
    public DbSet<A> As { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<B>().HasMany(b => b.Cees).WithMany(); // <-- THE SOLUTION
        base.OnModelCreating(modelBuilder);
    }

    public Context(string nameOrConnectionString)
        : base(nameOrConnectionString)
    {
    }
}

我意识到这对于任何在 EF 中经验丰富的人来说都是非常基本的东西,但我会继续并将其标记为答案,以便其他人将来可以节省一些时间来寻找这些信息。

谢谢

于 2014-02-06T11:55:10.210 回答