Entityframework是否在创建时自动分配导航属性

时间:2015-04-08 10:16:02

标签: c# entity-framework

当我运行下面提到的代码时,EF会使用正确的PersonAddress保存PersonId。我有 NOT PersonAddress实体添加到Person实体,即使我没有这样做,我的数据库中的记录也正确链接。

我的问题是:即使我没有指定它所属的实体,EF 会自动添加相关实体吗?如果是这样,这不会导致不需要的实体关系吗?

更新

由于以下原因,似乎正确保存了实体:

  1. 创建实体Person时,PersonId字段为0
  2. 创建时
  3. PersonAddress.PersonId也为0。
  4. 通过在创建时手动将Person.PersonId设置为任意值,然后将PersonAddress.PersonId设置为Person.PersonId相同的值,EF会正确保存数据,因为它们共享相同的{ {1}}。

    因此从技术上讲,EF会自动添加相关实体,因为它们共享相同的PersonId,所以它们是相关的。

    请参阅以下代码作为参考:

    PersonId

    当我在代码中添加额外的 using (var context = new Models.TestEntities()) { var person = context.People.Create(); var postalAddress = context.PersonAddresses.Create(); postalAddress.AddressLine1 = "PostalAddressLine1"; var residentialAddress = context.PersonAddresses.Create(); residentialAddress.AddressLine1 = "ResidentialAddressLine1"; context.People.Add(person); context.PersonAddresses.Add(postalAddress); context.PersonAddresses.Add(residentialAddress); context.SaveChanges(); } 时,出现以下错误: enter image description here
    代码:

    Person

    由于指定的错误,Entityframework现在无法确定 using (var context = new Models.TestEntities()) { var person = context.People.Create(); var person2 = context.People.Create(); var postalAddress = context.PersonAddresses.Create(); postalAddress.AddressLine1 = "PostalAddressLine1"; var residentialAddress = context.PersonAddresses.Create(); residentialAddress.AddressLine1 = "ResidentialAddressLine1"; context.People.Add(person); context.People.Add(person2); context.PersonAddresses.Add(postalAddress); context.PersonAddresses.Add(residentialAddress); context.SaveChanges(); } 个实体属于谁。

    我可以通过修改代码来解决这个问题:

    PersonAddress

    请参阅下面的EDMX:

    enter image description here

    请参阅用于创建两个表的SQL脚本:

            using (var context = new Models.TestEntities())
            {
                var person  = context.People.Create();
                var person2 = context.People.Create();
    
                var postalAddress           = context.PersonAddresses.Create();
                postalAddress.AddressLine1  = "PostalAddressLine1";
    
                var residentialAddress          =    context.PersonAddresses.Create();
                residentialAddress.AddressLine1 = "ResidentialAddressLine1";
    
                context.People.Add(person);
                context.People.Add(person2);
    
                person.PersonAddresses.Add(residentialAddress);
                person.PersonAddresses.Add(postalAddress);
    
                context.SaveChanges();
            }
    

    请参阅下面的Id栏截图: enter image description here enter image description here enter image description here

    请参阅下面的SQL Server Profiler跟踪:

    CREATE TABLE Person ( PersonId INT IDENTITY(1,1) NOT NULL CONSTRAINT [PK_Person] PRIMARY KEY, FirstName VARCHAR(250) ) CREATE TABLE PersonAddress ( PersonAddressId INT IDENTITY(1,1) NOT NULL CONSTRAINT [PK_PersonAddress] PRIMARY KEY, PersonId INT NOT NULL, AddressLine1 VARCHAR(250) ) ALTER TABLE PersonAddress ADD CONSTRAINT [FK_PersonAddress_Person] FOREIGN KEY(PersonId) REFERENCES [Person](PersonId)
    enter image description here

    Person
    enter image description here

    PersonAddress
    enter image description here

    请参阅SQL中插入的记录:

    PersonAddress
    enter image description here

    Person
    enter image description here

    感谢。

4 个答案:

答案 0 :(得分:3)

以下是发生的事情:

var person = context.People.Create();

创建Person PersonId = 0。

var postalAddress           = context.PersonAddresses.Create();
postalAddress.AddressLine1  = "PostalAddressLine1";
var residentialAddress          = context.PersonAddresses.Create();
residentialAddress.AddressLine1 = "ResidentialAddressLine1";

创建地址,同时PersonId = 0。

context.People.Add(person);
context.PersonAddresses.Add(postalAddress);
context.PersonAddresses.Add(residentialAddress);

EF已执行关系修正,即它已匹配地址'PersonIdPerson的{​​{1}}(全0)并建立了他们之间的联系。

PersonId

数据库已为context.SaveChanges(); 分配了标识值。 EF将其从数据库读回实体。

在第二个代码段中有两个Person.PersonId的{​​{1}} = 0,所以现在EF不知道将地址与哪个人关联。

怎么做

显然,这是出乎意料的行为。最好的办法是明确地将实体关联起来,如果它们是相关的,就像在你的第三个片段中一样。

一旦您了解这些自动关联,您可能希望通过为0以外的Person分配不同的默认值来阻止它们,例如-1。现在EF不会将此id与任何其他具有整数默认值0的外来值匹配。

答案 1 :(得分:1)

我已经针对我使用您的脚本创建的新数据库创建了一个新项目来测试该场景。然后我生成了一个反对它的模型,所有默认值。

以下是我用来创建人员和地址的代码。

        var entities = new TestEntities();

        var person = entities.People.Create();
        person.FirstName = "xxx";
        entities.People.Add(person);

        var address1 = entities.PersonAddresses.Create();
        address1.AddressLine1 = "Line1";
        entities.PersonAddresses.Add(address1);

        var address2 = entities.PersonAddresses.Create();
        address2.AddressLine1 = "Line1";
        entities.PersonAddresses.Add(address2);

        entities.SaveChanges();

我可以确认此代码确实运行并插入一个人和两个与该人相关联的地址。如果只有一个实体可以链接到它,它肯定看起来像EF连接它。我不确定这是否应该是一个功能,但它可以带来一些令人讨厌的惊喜。

答案 2 :(得分:0)

如果你没有指定第二个实体是什么,没有EF不能自动添加相关实体,原因是数据库中的数据完整性约束,希望这有帮助。

答案 3 :(得分:0)

在这里,您将两个人实体附加到上下文

context.People.Add(person);
context.People.Add(person2);

在这里,您将两个地址附加到第一个人实体

person.PersonAddresses.Add(residentialAddress);
person.PersonAddresses.Add(postalAddress);

所以基本上你告诉实体框架你要将这两个地址映射到第一个人。如果您不这样做,除非在地址中手动输入personID,否则实体框架不会映射它们

在您的第一个代码中,您只创建人员和地址,并尝试将其添加到数据库中。它们之间没有映射,实体框架不知道它们应该被链接。