EF不会根据我的模型

时间:2016-04-14 11:26:57

标签: c# entity-framework entity-framework-6 datacontext seeding

首先,我创建了一个仅包含基本属性的Person模型:

[Table("SGDB_Persons")]
public class Person {
    public int Id { get; set; }

    [Required]
    public string Firstname { get; set; }

    [Required]
    public string Lastname { get; set; }

    [Required]
    public Department Department { get; set; }

    [Required]
    public SourceType SourceType { get; set; }

在我注意到我遗漏了一些东西后,我添加了一个新的PersonData属性:

[Required]
    public PersonData PersonData { get; set; }

不幸的是,EF根本不会更新数据库 - 最初包含Person类型对象的PersonData已更新,因此不再有Person属性。另一方面,EF不会为PersonData_Id创建新列。

enter image description here

此外,ID列不会自动递增(所有其他表的Id列都可以)。令我困惑的是下面的Constraing在我的Person表中创建:

  

CONSTRAINT [FK_dbo.SGDB_Persons_dbo.SGDB_PersonData_Id] FOREIGN KEY([Id])REFERENCES [dbo]。[SGDB_PersonData]([Id])

我尝试了一切(至少我是这么认为的)。我手动删除了所有表/整个数据库,重新安装了EF,执行了手动迁移,但似乎没有任何工作。

我认为这个问题导致我无法使用以下代码为我的数据库播种:

protected override void Seed(PersonContext context) {
        base.Seed(context);
        var dep = new DepartmentContext().Departments.First();

        var status = new Status("Test");
        var persondata = new PersonData(status);
        context.Status.Add(status);
        context.PersonData.Add(persondata);
        for (int i = 0; i < 10; i++) {
            var person = new Person {
                Firstname = $"TestPersonFirstname{i}",
                Lastname = $"TestPersonLastname{i}",
                SourceType = COM.SourceType.Manual,
                Department = dep,
                PersonData = persondata
            };
            context.Persons.Add(person);
        }
        context.SaveChanges();
    }

每次执行此代码时,我都会遇到异常:

  

元数据集合中不存在具有标识“SGDB.DAL.Contexts.Person_Department”的成员。参数名称:identity。

我不知道这两个问题是否与同一问题有关,但两者都需要解决:)

提前致谢!

更新1

我的解决方案分为几个不同的项目:

BLL,DAL,COM,UI

DataContexts位于DAL项目内,COM项目内的模型。

部门模型:

[Table("SGDB_Departments")]
public class Department {
    public int Id { get; set; }

    [Required]
    public string Costcenter { get; set; }

    [Required]
    public string Abbreviation { get; set; }

    public string Description { get; set; }

    public string FullDepartmentName {
        get {
            return $@"{Division.Abbreviation}\{Abbreviation}";
        }
    }
    [Required]
    public virtual Division Division { get; set; }
}

PersonData Model:

[Table("SGDB_PersonData")]
public class PersonData {
    public PersonData(Status status) {
        Status = status;
    }

    public int Id { get; set; }
    public DateTime Limit { get; set; }
    public Person Responsible { get; set; }
    [Required]
    public Status Status { get; set; }
}

Person表(如你所见)有一个Department_Id列(EF自动插入)。

澄清

Person对象包含PersonData对象,作为此Person的附加信息。一个人可能/可能没有负责人(因此PersonData.Responsible不是父人的导航属性)。 另外,如果可能的话,我不希望在PersonData表中有一个外键。

我发现我必须修改

modelBuilder.Entity<Person>()
       .HasRequired(e => e.PersonData)
       .WithRequiredPrincipal(e => e.Responsible)
       .WillCascadeOnDelete(true);

modelBuilder.Entity<Person>()
       .HasRequired(e => e.PersonData)
       .WithMany()
       .WillCascadeOnDelete(true);

如果它解决了我的问题,我会尝试并报告。

更新2

  

元数据集合中不存在具有标识“SGDB.DAL.Contexts.Person_Department”的成员。

1 个答案:

答案 0 :(得分:1)

您的模型定义one-to-onePerson之间的PersonData关系,以后需要和前者 - 可选。 EF始终将one-to-one关系的所需部分用作主体,将可选部分用作依赖。因此,它认为PersonaData是主体,Person - 依赖,并在数据库表设计中反映出来。

你需要相反的,双方都需要 。当双方都是必需的或可选的时,EF不能自动派生主要/从属方,并且无法通过数据注释(属性)指定,因此您需要一个流畅的API设置。

覆盖您的DbContext OnModelCreating并添加如下内容:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Person>()               
        .HasRequired(e => e.PersonData)
        .WithRequiredPrincipal(e => e.Responsible)
        .WillCascadeOnDelete(true);

    base.OnModelCreating(modelBuilder);
}

它的作用是告诉EF Person->PersonData关系的双方都是必需的,Person是委托人。这应该再次使您的Person.Id列自动增加,并且应该解决问题的人员数据部分。

我注意到的另一件事就是这一行:

var dep = new DepartmentContext().Departments.First();

而同一程序的所有其他部分都使用名为context的变量。这可能/可能不是问题,只需检查出来。

更新:根据更新后问题的说明,您发现PersonPersonData之间存在两个关系,因此您需要单独处理他们每个人的配置如下:

modelBuilder.Entity<Person>()
    .HasRequired(e => e.PersonData)
    .WithRequiredPrincipal()
    .WillCascadeOnDelete(true);

modelBuilder.Entity<PersonData>()
    .HasOptional(e => e.Responsible)
    .WithOptionalDependent() // or WithMany()
    .WillCascadeOnDelete(false);

请注意,PersonData表中无法引入其他FK列。需要表示Responsible关系,因此您最终会得到一个名为Responsible_Id的表格列。