代码之家  ›  专栏  ›  技术社区  ›  Jack

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

  •  0
  • Jack  · 技术社区  · 6 年前

    我有一个使用实体框架的ASP.NET MVC应用程序。我已经开发了两个模型,使用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)
    );
    

    所有这些工作都很好,我可以将数据绑定到我的模型,编辑字段等等。我的问题是,如果我试图为这些模型创建记录,那么当子模型的外键在父模型中时,如果我同时创建它们,那么如何才能做到这一点呢?

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

    1. 获取 PARENT 要插入数据库的模型
    2. 插入 起源 模型
    3. 呼叫 SaveChanges()

      • 对于每个家长:

        1. 为父级获取FK
        2. 获取要插入数据库的子模型列表
        3. 对于每个子模型,使用该FK插入子模型
        4. 呼叫 SaveCechange()
    4. 其他模型的其他操作和数据库更新

    5. 呼叫 SaveCechange()

    我相信我可以优化它,但这不是我关心的。在我看来,有一些方法可以做到这一点,而无需手动查找FK或手动设置FK。如果必须的话,我可以这样做,但我只想用一个 SaveCechange() 调用在单个事务中强制执行这些命令。我在找一些符合以下条件的东西:

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

      • 为每一位家长
        1. 插入父项并返回新FK(不保存)
        2. 获取要插入数据库的子模型列表
        3. 对于每个子模型,使用该FK插入子模型
    2. 其他模型的其他操作和数据库更新

    3. 呼叫 SaveCechange()

    为了提供一些上下文,我的实际表中有许多列不能保证是唯一的(这就是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个子记录,那么我的子表中应该有9个新记录。但是,在这段代码之后,对于第一个父级,我只有3条记录。

    我假设这与我重复使用相同的子列表有关,并且实体框架以某种方式将它们视为重复项。我将它移动到父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 回复  |  直到 6 年前
        1
  •  1
  •   Moho    6 年前

    使用navigation属性;将__child.parent_nav属性设置为尚未保存的__parent_实体,并且ef将以正确的顺序插入它们,只需调用一次__savechanges_

        2
  •  0
  •   LazZiya    6 年前

    我使用下面的代码为一个国家表输入初始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();
    
    推荐文章