实体框架 - 同时使用 FK 插入父模型和子模型



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

伪代码:

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 模型,在该 FK 中插入 CHILD。
      4. 呼叫SaveChanges()
  4. 其他模型的其他操作和数据库更新

  5. 呼叫SaveChanges()

我相信我可以优化它,但这不是我关心的。在我看来,应该有一些方法可以做到这一点,而无需手动查找 FK 或手动设置 FK。如果必须,我可以这样做,但我只想使用一个SaveChanges()调用在单个事务中推送这些命令。我正在寻找类似以下内容的内容:

  1. 获取要插入到数据库中的父模型列表

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

  3. 呼叫SaveChanges()

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

有什么建议吗?

谢谢

编辑:所以我更改了我的代码以按照建议使用导航属性。这几乎有效。这是我的代码:

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 条父记录和 3 条子记录,则我的 CHILD 表中应该有 9 条新记录。但是,在此代码之后,我只有 3 条记录用于第一个 PARENT。

我假设这与我重复使用相同的子项列表并且实体框架以某种方式将它们视为重复项这一事实有关。我按如下方式将其移动到 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((函数相当麻烦。有什么想法吗?

使用导航属性;将"Child.Parent"导航属性设置为尚未保存的"父"实体,EF 将通过对"保存更改"的一次调用以正确的顺序插入它们

我使用以下代码为国家/地区表播种初始 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();

最新更新