代码之家  ›  专栏  ›  技术社区  ›  John Darvill

实体框架代码优先-具有循环关系的奇怪行为

  •  1
  • John Darvill  · 技术社区  · 10 年前

    我很难理解Code First如何基于模型建立关系。下面是模型:

    public class Person
    {
        [Key]
        public string PersonName { get; set; }
    
        [Required]
        public virtual Nation NationOfBirth { get; set; }
    
        [Required]
        public virtual Nation CurrentNationOfResidence { get; set; }
    }
    
    public class Nation
    {
        [Key]
        public string NationName { get; set; }
    
        public virtual Person CurrentSecondInCommand { get; set; }
    }
    

    起初,我在创建数据库时遇到了一个错误,我可以通过添加几个modelBuilder命令来解决这个问题:

    modelBuilder.Entity<Person>()
        .HasRequired(p => p.NationOfBirth)
        .WithRequiredDependent()
        .WillCascadeOnDelete(false);
    modelBuilder.Entity<Person>()
        .HasRequired(p => p.CurrentNationOfResidence)
        .WithRequiredDependent()
        .WillCascadeOnDelete(false);
    

    我还补充道:

    modelBuilder.Entity<Nation>()
        .HasOptional(n => n.CurrentSecondInCommand)
        .WithOptionalDependent()
        .WillCascadeOnDelete(false);
    

    现在,当我尝试用以下代码填充数据库时:

    var america = new Nation { NationName = "America" };
    context.Nations.Add(america);
    var bush = new Person { PersonName = "Bush", CurrentNationOfResidence = america, NationOfBirth = america };
    var obama = new Person { PersonName = "Obama", CurrentNationOfResidence = america, NationOfBirth = america };
    var biden = new Person { PersonName = "Biden", CurrentNationOfResidence = america, NationOfBirth = america };
    context.People.Add(bush);
    context.People.Add(obama);
    context.People.Add(biden);
    context.SaveChanges();
    

    在添加“bush”时,CurrentNationOfResidence和NationOf Birth属性对他来说都不为空,并设置为“america”对象。但一旦添加“奥巴马”,“布什”上的CurrentNationOfResidence和NationOf Birth属性都将变为空。一旦加上“拜登”,“奥巴马”也会发生同样的情况。

    如果我检查由此生成的数据库,我看不到在People表上创建的任何外键列,但我本以为Code First会自动为Person上的两个Nation字段生成2个外键(这就是我认为我的前两个modelBuilder命令会做的事情-根据“WithRequiredDepedent”的描述)。更奇怪的是,有一个叫“美国”的人被添加到了数据库中,还有一个叫美国的国家。

    如果有人能提供我的模型的建议,我真的非常感谢。我意识到我在这里有一种循环关系,但我会认为这没关系,因为各国不需要拥有CurrentSecondInCommand。我意识到这个词有点复杂(或者说“复杂”是一个更好的词),但我认为这是有道理的:

    • 一个人必须有一个(Nation)NationOfBirth。
    • 一个人必须有一个(国家)CurrentNationOfResidence。
    • 一个国家可以选择有一个(个人)CurrentSecondInCommand。

    任何建议都非常欢迎,谢谢。

    2 回复  |  直到 10 年前
        1
  •  1
  •   tede24    10 年前

    人与国家之间的两种关系不是一对一,而是多对一:

    • 一个人必须有一个(Nation)NationOfBirth。但是一个国家有很多人出生在那里
    • 一个人必须有一个(国家)CurrentNationOfResidence。但是一个国家有很多居民

    因此,您的配置应该是:

    modelBuilder.Entity<Person>()
        .HasRequired(p => p.NationOfBirth)
        .WithMany()
        .WillCascadeOnDelete(false);
    modelBuilder.Entity<Person>()
        .HasRequired(p => p.CurrentNationOfResidence)
        .WithMany()
        .WillCascadeOnDelete(false);
    
        2
  •  0
  •   Ivelin Ivanov    10 年前

    Nation类中的虚拟财产必须是 ICollection<Person> CurrentSecondInCommand 这样,数据库中将有“一个国家的许多人”,关系将是“一对多”而不是“一对一”