代码之家  ›  专栏  ›  技术社区  ›  CodeWarrior

使用组合键的一部分的单向一对多关系

  •  0
  • CodeWarrior  · 技术社区  · 7 年前

    Person
        PK Guid Id
        PK DateTime DateSynced
    
    Test
        PK Guid Id
        FK Guid PersonId
    

    在EntityFramework6.2中,我实际上只关心Person上引用一组测试的导航属性。我不需要试验人员或者类似的事情。

    我真的只想人员。测试哪里测试.拟人ID=Id,与日期同步无关。最终会有许多人拥有相同的Id,每个人都有不同的datesynchronized DateTime。

    这是可行的还是我需要一个中间表的多对多?

    我知道EFCore有一个备用密钥的概念,我想我可以在这项工作中利用它,但在ef6.2中似乎没有相应的功能

    编辑

    在我的onmodel创建覆盖中有以下Fluent规则。

    modelBuilder.Entity<Test>()
        .HasRequired(t => t.Person)
        .WithMany(p => p.Tests)
        .HasForeignKey(t => t.PersonId);
    

    我得到以下异常,抱怨依赖和主要角色约束:

    The number of properties in the Dependent and Principal Roles in a relationship constraint must be identical.

    据我所知,这是因为我引用的实体只有一部分是由两部分组成的复合键。我要找的是一种能做到这一点的方法。

    0 回复  |  直到 7 年前
        1
  •  2
  •   Steve Py    7 年前

    第二个表上的外键必须与第一个表上的主键匹配。

    如果我有一个人的PK是ID:1,同步日期:2019-05-22

    如果我要添加一个“Test”记录,它将引用FK Person ID为1的哪个Person记录?它将引用两个记录,因此EF不能支持指向单个人员记录的“HasRequired”引用。

    要引用Person ID 1的一个变体,测试记录将需要PersonId和SyncDate来标识该记录:

    public class Test
    {
        public Guid Id { get; set; }
        public Guid PersonId { get; set; }
        public DateTime SyncDate { get; set; }
    
        public virtual Person Person { get; set; }
    }
    
    modelBuilder.Entity<Test>()
        .HasRequired(t => t.Person)
        .WithMany(p => p.Tests)
        .HasForeignKey(t => new { t.PersonId, t.SyncDate });
    

    数据库中的表不能基于部分FK相互引用,除非是多对1。即。

    Person
    ------
    PK: PersonID
    
    PersonComment
    -----------
    PK: PersonId
    PK: CommentDate
    

    在具有以下特性的表结构中:

    Person
    ------
    PK: PersonID
    PK: Version
    
    PersonComment
    -------------
    PK: PersonCommentID
    PersonId
    

    PersonComment中的PersonId不能是FK to Person,因为它不反映Person表的PK。您可以合法地拥有这个表结构,但PersonId只是一个愚蠢的、不受约束的列。您可以使用它手动查询所有人员记录,但您将获得该人员的所有版本。没有约束等来确保注释上的Person ID与Person表上的ID匹配。

    如果您不关心Person的版本,那么可以使用Person ID作为测试实体,但EF无法将其与Person实体相关联,则必须从上下文手动加载Person记录。

    当谈到架构结构背后的目的时,我建议寻找可能的替代方案。例如,如果您的目标是跟踪版本化的数据,我建议您查看以下内容:

    Person
    PK: PersonId
    ** Person Fields
    
    PersonHistory
    PK: PersonHistoryId
    FK: PersonId
    VersionDate
    ** Person Fields
    
    Test
    PK: TestId
    FK: PersonId (if applies to current person, or PersonHistoryId if a specific version)
    

    然后“人”反映了人的现状,包含了一个反映历史的收藏。从这里可以防止通过私有setters和DDD样式的方法修改Person字段,这些方法负责在更新Person值之前根据当前的Person数据组成一个新的历史记录。这样一来,个人记录就可以是历史记录,并为相关实体保留其ID。

    推荐文章