如何在代码优先共享EF6对象

时间:2014-02-05 15:57:21

标签: c# associations entity-framework-6 cardinality

我刚开始从代码优先方案中自学Entity Framework(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。我确实意识到我可以通过网络来解决这个问题,但如果有人能指出我正确的方向,我会非常感激。

干杯

1 个答案:

答案 0 :(得分:0)

Gert建议我向C课程添加一个集合属性,从而使我走上正轨。实际上,这足以让EF / CF自动识别BC之间的多对多关系。但代码优先的全部意义在于设计一个类的域模型,然后让EF持久化它们,而不必使用持久性信息将它们陷入困境。

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

因此,我使用流畅的API进行了更多实验,并意识到我错过了.WithMany()的无参数重载。我正在寻找一种通用形式,这样就可以指定多对多关系的另一种类型。在我看来,我会写:modelBuilder.Entity<B>.HasMany(b => b.Cees).WithMany<B>()。事实证明,WithMany()的无参数重载就是出于这个目的,因为此场景中的类型C已由第一个HasMany()部分指定。

因此,总而言之,EF将识别类BC之间的多对多关系,而不需要使用额外的通用“乱丢”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中经验丰富的人来说是非常基本的东西,但我会继续将此标记为答案,以便其他人可以节省一些时间来寻找这些信息。

由于