Entity framework 如何获得组合可选关系和一对多关系?

Entity framework 如何获得组合可选关系和一对多关系?,entity-framework,foreign-keys,relationships,data-modeling,Entity Framework,Foreign Keys,Relationships,Data Modeling,我对如何在实体框架中建模我的关系感到困惑 我希望ClassA可以选择性地指向aClassB。 这听起来像是一种可选的一对一关系 我还希望ClassB始终指向指向它的ClassA。 我还想允许多个ClassB引用同一ClassA。这听起来像是一对多的关系 这是一种关系,还是两种完全不同的关系 如果是两个关系,它们能否共享ClassB上显示的用于引用ClassA的单个属性“ClassAKey” 在我的问题中,我的头脑中清楚地知道我希望我的OM是什么: ClassA { [Key] i

我对如何在实体框架中建模我的关系感到困惑

我希望
ClassA
可以选择性地指向a
ClassB
。 这听起来像是一种可选的一对一关系

我还希望
ClassB
始终指向指向它的ClassA。 我还想允许多个
ClassB
引用同一
ClassA
。这听起来像是一对多的关系

这是一种关系,还是两种完全不同的关系

如果是两个关系,它们能否共享ClassB上显示的用于引用ClassA的单个属性“ClassAKey”

在我的问题中,我的头脑中清楚地知道我希望我的OM是什么:

ClassA
{
    [Key]
    int Key { get; set; }
    ClassB Maybe { get; set; }
    int MaybeKey { get; set; }
}

ClassB
{
    [Key]
    int Key { get; set; }
    ClassA Always { get; set; }
    int AlwaysKey { get; set; }
}
我的头脑中也很清楚DB中应该是什么样子:对于
ClassB
应该只有一个
ClassAKey
列,对于
ClassA
应该只有一个
ClassBKey
列,这样每个列都可以相互引用,并且在这些列上有外键关系

但是。。。我不清楚如何在EF中对此进行建模。 事实上,看起来我一定是做错了什么! 如果我只是从上面的代码开始,我会得到一个错误

无法确定类型“ClassA”和“ClassB”之间关联的主端。必须使用关系fluent API或数据批注显式配置此关联的主端。

如果我尝试这样配置它

modelBuilder.Entity<ClassA>()
            .HasOptional(a => a.Maybe)
            .WithRequired(b => b.Always);
应该是t.AlwaysKey,对吧?
发生什么事了

如果我理解正确,您正试图在
ClassA
ClassB
之间创建一个:多个可选关系。听起来你总是希望
ClassB
有一个相关的
ClassA
,这将使
ClassA
成为你的委托人,而
ClassB
成为你的依亲亲属

首先,您必须更改
ClassB
的导航属性(在
ClassA
中)。由于您需要多个关系,因此需要某种集合来存储
ClassB
对象

这意味着您将删除
ClassA
中的
MaybeKey
,因为您所引用的对象不是一个,而是一个集合(例如
ICollection
)。您也不需要相应的
ClassA
表中的一列来引用
ClassB
(因为它是一个一对多关系,单个列不起作用)。在
ClassB
表中应该只需要有一个外键列,它指的是与
ClassB
相关的
ClassA

您的代码可能如下所示:

public class ClassA
{
    [Key]
    public int Key { get; set; } // ClassA Key

    public virtual ICollection<ClassB> MyClassBs { get; set; } // Your optional dependants.
}

public class ClassB
{  
    [Key]
    public int Key { get; set; } // ClassB key

    public int AKey { get; set; } // Your foreign key.
    public virtual ClassA myClassA { get; set; } // Your principal.
}
有几种不同的表达方式(例如,您可以从
ClassB
侧进行)

对于主键,可能需要使用稍微传统一点的命名,例如
ID
,而对于外键,则需要使用
ClassAID
等名称,因为Entity framework有许多可供使用的名称。它还使其他人更容易阅读您的代码(因为您往往会遇到类似的约定)

编辑:更新以包括“特殊”关系

ClassA
中,您可以包含以下字段(您在原始示例中已经使用了不同的名称):

并添加以下映射:

modelBuilder.Entity<ClassA>()
            .HasOptional(x => x.SpecialB)
            .WithMany()
            .HasForeignKey(x => x.SpecialBID);

最后,我认为这是应该起作用的,但我没有让它起作用(这可能是Entity Framework 5中的一个bug):


第二个可选关系是按约定工作的,而不是显式配置。

我不确定是否能得到它,但如果您尝试从现有数据库生成.edmx,会得到什么?嗯,有趣的答案。我的意见是,我实际上不应该需要MyClassB的集合。我不确定如果我懒散地加载了该集合并且从不使用它,那么它是否会带来很大的伤害。你的答案也遗漏了一件对我来说很重要的事情,那就是ClassA没有选择地拥有一个关联的ClassB,它是其集合中的“特殊”成员。这肯定对我有帮助!它变得有点复杂,但里面可能有一些有用的东西
modelBuilder.Entity<ClassA>()
            .HasMany(b => b.MyClassBs)     // Many ClassBs
            .WithRequired(a => a.myClassA) // Each ClassB requires a ClassA
            .HasForeignKey(b => b.AKey);   // Use Akey as a foreign key
public int SpecialBID { get; set; }
public virtual ClassB SpecialB { get; set; }
modelBuilder.Entity<ClassA>()
            .HasOptional(x => x.SpecialB)
            .WithMany()
            .HasForeignKey(x => x.SpecialBID);
    modelBuilder.Entity<ClassB>()
        .HasRequired(x => x.myClassA)
        .WithMany()
        .HasForeignKey(x => x.AKey);
modelBuilder.Entity<ClassB>()
    .HasRequired(a => a.Always)
    .WithMany()
    .HasForeignKey(a => a.AlwaysKey);

modelBuilder.Entity<ClassB>()
    .HasOptional(b => b.Maybe);
modelBuilder.Entity<ClassB>()
    .HasRequired(a => a.Always)
    .WithMany()
    .HasForeignKey(a => a.AlwaysKey);

//modelBuilder.Entity<ClassB>()
//    .HasOptional(b => b.Maybe);
 int? MaybeKey { get; set; }