【问题标题】:Entity Framework model class has conditional one-to-one relationshipEntity Framework 模型类有条件的一对一关系
【发布时间】:2014-08-10 14:46:13
【问题描述】:

我需要一些帮助。根据我对项目的想法,我在创建模型时遇到了重大问题。为简化起见,我有一个 Parent 表、一个 Student 表和一个 Address 表。因此,每个家长记录可以有多个学生并且只有一个地址。每个学生记录可以有多个家长,并且只有一个地址。从逻辑上讲,我真的不能假设学生地址与父母地址相同,因为可能有一个学生的父母住在不同的地方。所以,我希望能够有一个学生的地址以及每个家长的地址。所以,我基本上设想这个数据库布局归结为一个地址表,带有地址 ID、街道、城市、州、邮编。然后是一个学生表,带有学生 ID、姓名、地址 ID。然后是带有 ParentID、name、addressID 的 Parent 表。然后是 Parent_Student 参考表,包含 StudentID 和 ParentID。

那么,关于如何实现这一点有什么想法吗?我只用地址信息和 ID 创建了我的地址模型。我使用 ID、姓名、虚拟地址和虚拟 ICollection 父级创建了我的学生模型。然后使用 ID、名称、虚拟地址和虚拟 ICollection 创建了我的父模型。当我尝试通过 New->Scaffolded Item 创建我的 Student 控制器时,我收到一条错误消息,指出 VS 无法确定 Parent 和 Address 类型之间关联的主体端。

我假设这与地址记录对父母或学生有一个外键这一事实有关,但不是两者都有。我对整个代码优先的方法很陌生,所以任何见解都将不胜感激。提前致谢!


编辑:添加更新代码

人物模型:

public enum PersonType
{
    Student, Parent, Teacher
}

public abstract class Person
{

    [Key]
    public int PersonId { get; set; }

    [Required]
    [StringLength(50,ErrorMessage = "First Name cannot be longer than 50 characters.")]
    [Display(Name= "First Name")]
    public string FirstName { get; set; }

    [StringLength(50, ErrorMessage = "Middle Name cannot be longer than 50 characters.")]
    [Display(Name = "Middle Name")]
    public string MiddleName { get; set; }

    [Required]
    [StringLength(50, ErrorMessage = "Last Name cannot be longer than 50 characters.")]
    [Display(Name = "Last Name")]
    public string LastName { get; set; }
    public PersonType personType {get; set;}

    public Address Address { get; set; }

    [Display(Name = "Full Name")]
    public string FullName
    { 
        get
        {
            return FirstName + " " + LastName;
        }
    }

    [Display(Name = "Full Name w Middle")]
    public string FullNameWMid
    { 
        get
        { 
            return FirstName + " " + MiddleName + " " + LastName;
        }
    }
}

学生模型:

public class Student : Person
{
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:mm-dd-yyyy}", ApplyFormatInEditMode = true)]
    [Display(Name = "Birthday")]
    public DateTime Birthday { get; set; }
    public ICollection<int> ParentList { get; set; }

    public virtual ICollection<Parent> Parents { get; set; }
    public virtual Teacher Teacher { get; set; }


}

父模型:

public class Parent : Person
{       
    public string EmailAddress { get; set; }
    public ICollection<int> StudentList { get; set;  }

    public virtual ICollection<PhoneNumber> PhoneNumbers { get; set; }
    public virtual ICollection<Student> Students { get; set; }

}

地址模型:

public class Address
{
    public int AddressId { get; set; }
    public string StreetLine1 { get; set; }
    public string StreetLine2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }

    public Person Person { get; set; }

}

【问题讨论】:

  • 您能否将您的实体的代码粘贴到问题中?
  • 你可以有两个表,外键引用同一个表。可能是代码有问题,而不是设计问题

标签: c# asp.net-mvc entity-framework-6 foreign-key-relationship


【解决方案1】:

是的,你会遇到很多问题。首先,Entity Framework 仅在使用“共享主键”时支持 1:1 关系。这意味着地址 ID 和家长或学生 ID 必须相同,并且地址必须是另一个的外键。

我知道为每个属性创建导航属性似乎很容易,并且您应该有一个 1:1 的比例,但是您必须考虑如何在数据库中创建它。它实际创建的是两个独立的 1:many 关系。而且,由于没有什么可以阻止您将多个实体分配给多端,这会导致 EF 不支持的情况。

这当然会使事情变得困难,因为您有多个表要链接地址。

我建议改为创建一个 Student 和 Parent 都派生自的“Person”实体,然后使用 TPH 或 TPC 继承来创建 Student 和 Parent 的唯一实体。

这允许您的父母和学生共享一个公共 ID,然后您可以将其用作与您的地址实体的 1:1 共享密钥。

您可以在这里找到更多信息:

http://blog.bennymichielsen.be/2011/06/02/entity-framework-4-1-one-to-one-mapping/

【讨论】:

  • 感谢您的评论。我最初尝试以这种方式实现,但遇到了问题,因此决定尝试单独定义,然后在我开始使用后转回。发表评论后,我回去了。我收到与以前相同的错误,关于 EF 无法确定类型“Person”和“Address”之间关联的主体端。我显然这里还有其他问题。我必须混淆我的模型中必须具有物理属性的事实,而不是“虚拟”导航属性。我将用我的新课程更新我的初始帖子,以供参考。
  • @user3876675 - 将 PersonId 和 AddressId 更改为两者中的 Id。将 Address 的 Id 作为主键,同时作为 Person 表的 Id 的外键。您还需要确保 Address Id 不是 Identity 列(不是自动生成的),因为它必须与 Person Id 具有相同的值。我提供的链接准确地显示了如何做到这一点。
【解决方案2】:

首先,我认为命名不合适。将父母与学生联系起来没有任何意义,我认为应该是父母和孩子。并且在它们中提供 ID 属性作为主键使得维护非常困难。但是,让我们尝试按照您的方式实现它。

将类设为具有 ID、全名、名字和姓氏、门牌号等一般信息的公共属性。这样做会给出一个主键(ID)和一个外键(门牌号)。现在您已经与 Address 类建立了 1:1 的关系。

在您给出的上述学生和家长类模型中,我发现没有这样的属性可以将学生与其家长相关联,反之亦然。现在您创建类 Parent 和 Student,例如: 父类具有 ID 的整数集合属性(ParentOfStudentsList),类似地,Student 类具有一个整数集合属性来保存与(StudentOfParentsList)相关联的父母的所有 ID,这样做可以让您拥有一对多和多对一的关系家长和学生之间。

注意:一定要在 Parent 和 Student 中派生 Person 类。我希望这个解决方案对你有用。

【讨论】:

  • 感谢 cmets。我没有与每个关联的列表,我确实有虚拟导航属性。在我的上下文中,我确实定义了一个流畅的关系,如下所示。这是否足够? modelBuilder.Entity&lt;Parent&gt;() .HasMany(p =&gt; p.Students).WithMany(s =&gt; s.Parents) .Map(t =&gt; t.MapLeftKey("PersonID") .MapRightKey("PersonID") .ToTable("ParentStudent"));
  • 查看您的 lambda 表达式,我猜您尝试获取每个学生记录并将学生的个人 ID 与其父母的个人 ID 映射。我不确定查询,但这里的逻辑似乎是正确的。
猜你喜欢
  • 2017-02-17
  • 1970-01-01
  • 1970-01-01
  • 2019-08-07
  • 2021-09-25
  • 1970-01-01
  • 2016-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多