实体框架-同时插入带有FK的父子模型

时间:2018-10-02 19:25:48

标签: c# entity-framework sql-server-2008

我有一个使用实体框架的ASP.NET MVC应用程序。我使用SQL Server 2008 R2数据库的数据库优先(代码)方法开发了2个模型。一个模型本质上是父模型,另一个模型是子模型,其中包含指向父模型的数据库生成列的外键。

伪代码:

CREATE TABLE PARENT
(
    ROWID BIGINT IDENTITY(1,1) NOT NULL,
    VALUE NVARCHAR(255) NOT NULL,

    PRIMARY KEY(ROWID)
);

CREATE TABLE CHILD
(
    ROWID BIGINT IDENTITY(1,1) NOT NULL,
    PARENT_ROWID BIGINT NOT NULL,
    VALUE NVARCHAR(255) NOT NULL,

    PRIMARY KEY(ROWID),
    FOREIGN KEY(PARENT_ROWID) REFERENCES PARENT(ROWID)
);

所有这些都可以正常工作,并且我可以将数据绑定到我的模型并编辑字段等。我的问题是,如果我试图为这些模型创建记录,那么当CHILD的外键在PARENT中却无法同时创建时,该怎么办?

所以,我目前的基本步骤是:

  1. 获取要插入数据库的PARENT模型的列表
  2. 插入PARENT模型
  3. 致电SaveChanges()

    • 对于每个家长:

      1. 获得家长FK
      2. 获取CHILD模型列表以插入数据库中
      3. 对于每个CHILD型号,在CHILD中插入该FK
      4. 致电SaveChanges()
  4. 其他模型的数据库的其他操作和更新

  5. 致电SaveChanges()

我敢肯定我可以优化它,但这不是我所关心的。在我看来,应该有某种方法可以执行此操作,而无需手动查找FK或手动设置FK。如果需要,我可以这样做,但是我只想使用一个SaveChanges()调用来在单个事务中推送这些命令。我正在寻找符合以下条件的东西:

  1. 获取要插入数据库的PARENT模型列表

    • 每个家长
      1. 插入家长并返回新的FK(不保存)
      2. 获取CHILD模型列表以插入数据库中
      3. 对于每个CHILD型号,在CHILD中插入该FK
  2. 其他模型的数据库的其他操作和更新

  3. 致电SaveChanges()

为了提供一些上下文,我的实际表中有许多列不能保证是唯一的(这就是为什么PK位于ROWID上的原因),并且这些行中的每一行都与子表具有非多对多的关系,其中子表也可能具有非唯一的行。并不是很理想,但是到目前为止,这是我们运营所需要的。我在此处包括伪代码,因为实际的代码是专有的,但是如果需要,我可能可以创建一个真实的模型。

有什么建议吗?

谢谢

编辑: 因此,我根据建议更改了代码以利用Navigation属性。这几乎可行。这是我的代码:

List<PARENT> parents = getParents();
List<CHILD> children = getChildren();
foreach (PARENT parent in parents)
{
    db.PARENT.add(parent);
    foreach (CHILD child in children)
    {
        child.PARENT = parent;
        db.CHILD.add(child);
    }
}

db.SaveChanges();

乍一看,这正是我想要的。但是,当我运行它时,子记录仅插入第一个父记录。因此,例如,如果我有3个PARENT记录和3个CHILD记录,那么我的CHILD表中应该有9个新记录。但是,在这段代码之后,第一个PARENT只有3条记录。

我假设这与以下事实有关:我反复使用相同的子级列表,而Entity Framework却以某种方式将其视为重复项。我将其按如下所示移动到PARENT for循环中,并且按预期工作:

List<PARENT> parents = getParents();
foreach (PARENT parent in parents)
{
    db.PARENT.add(parent);
    List<CHILD> children = getChildren();
    foreach (CHILD child in children)
    {
        child.PARENT = parent;
        db.CHILD.add(child);
    }
}

db.SaveChanges();

但是,我不希望这样做,因为getChildren()函数相当麻烦。有什么想法吗?

2 个答案:

答案 0 :(得分:1)

使用导航属性;将“ Child.Parent”导航属性设置为尚未保存的“ Parent”实体,EF会通过一次调用“ SaveChanges”的操作按正确的顺序插入它们。

答案 1 :(得分:0)

我使用下面的代码为一个国家表播种了初始dB值,该国家表中的城市,地区,邻里及其转换在一个dB内。

您可以实现类似的结构,以在同一dB调用中创建父代->子代->孙子实体;

            var country = new MyCountry {
                Title ="Syria",
                ShortName="SYR",
                 Translations=new[]
                 {
                     new CountryTranslate { LCID=1, Name="سوريا" },
                     new CountryTranslate { LCID=31, Name="Suriye" },
                     new CountryTranslate {LCID=9, Name="Syria" }
                 },
                  Cities=new[]
                  {
                      new MyCity
                      {
                          Title="Lattakia",
                          ShortName = "LAT",
                          Translations=new[]
                          {
                              new CityTranslate { LCID=1, Name="اللاذقية" },
                              new CityTranslate {LCID=31, Name="Lazkiye" },
                              new CityTranslate {LCID=9, Name="Lattakia" }
                          },
                          Districts=new[]
                          {
                              new MyDistrict
                              {
                                  Title="Owineh",
                                  Translations=new[]
                                  {
                                      new DistrictTranslate { LCID=1, Name="العوينة" },
                                      new DistrictTranslate { LCID=31, Name="Uveyne" },
                                      new DistrictTranslate {LCID=9, Name="Owineh" }
                                  },
                                  Neighborhoods = new[]
                                  {
                                      new MyNeighborhood
                                      {
                                          Title="Reji",
                                          Translations = new[]
                                          {
                                              new NeighborhoodTranslate { LCID=1, Name="الريجي"},
                                              new NeighborhoodTranslate { LCID=31, Name="Eski Reji"},
                                              new NeighborhoodTranslate { LCID=9, Name="Old Reji"}
                                          }
                                      }
                                  }
                              }
                          }
                      }
                  }
            }

context.SaveChanges();