实体框架单个查询插入子实体

时间:2015-08-18 11:54:00

标签: c# entity-framework-6

我正在学习使用C#POCO在版本6+上首先使用代码的实体框架(EF)。请考虑以下示例:

public class DatabaseContext : DbContext
{
    public virtual DbSet<TextElement> Textuals { get; set; }
}

public class TextElement
{
    [Key]
    public int                              Number   { get; set; }
    public string                           Content  { get; set; }
    public virtual ICollection<TextElement> Children { get; set; }
}

我想要做的是将新子项添加到现有父项。在伪SQL中我可以做类似的事情:

INSERT INTO Textuals (Content, ParentId) VALUES ("Lorem Ipsum", 42)

其中42是父记录的ID。

过去一天我一直在网上搜索,让EF在C#代码中为我做同样的事情。我能找到的最好的是:

using (var context = new  DatabaseContext())
{
    var parent = new TextElement { Number = 42, Children = new List<TextElement>() };
    var child  = new TextElement { Content = "I iz kiddo" };
    context.Textuals.Attach(parent);
    parent.Children.Add(child);
    context.SaveChanges();
}

但是,Attach调用似乎也会运行查询。同样的问题适用于按ID删除实体,同样需要Attach,运行不必要的查询。

是否有更好的替代方法来做我想要的:将子实体添加到现有父级?

更新

根据cverb的回答,我得到了以下代码,按照我的意愿行事:

public class TextElement
{
    [Key]
    public int                              Number   { get; set; }
    public string                           Content  { get; set; }
    public virtual ICollection<TextElement> Children { get; set; }
    // Added custom parent id reference, MUST be nullable to allow 
    // for entries without parent
    public int?                             ParentId { get; set; }
}

现在,因为这是一个破坏约定的名称(约定规定了TextElementId,它尽可能模糊)我需要用一点点“流畅的api”代码来改变Context。这明确定义了类中属性之间的关系。

public class DatabaseContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<TextElement>()
            .HasMany((e) => e.Children)        // Indicate the many relation
            .WithOptional()                    // Indicate that the many
                                               // relation is optional.
                                               // Don't require a nav prop
            .HasForeignKey((e) => e.ParentId); // The FK to use with the
                                               // relation.
    }

    public virtual DbSet<TextElement> Textuals { get; set; }
}

这使我能够成功应用迁移。

3 个答案:

答案 0 :(得分:2)

您应该在ParentId实体上明确添加TextElement

public int? ParentId { get; set; }

如果您不知道如何做到这一点,请在this page下的“了解一对多关系惯例”一节中提供一些很好的信息。

然后您只需使用以下代码即可添加新实体。

using (var context = new  DatabaseContext())
{
    var child  = new TextElement { Content = "I iz kiddo", ParentId = 42 };
    context.SaveChanges();
}

无需将子项附加或添加到父项Children - 列表中,因为实体框架将自行获取更改。

答案 1 :(得分:0)

您正在使用的方式是正确的方式......在这里,EF上下文为您完成所有工作:启动事务执行插入所需的编辑和删除,最后提交更改。

答案 2 :(得分:0)

继续这个

  

我想要做的是将新子项添加到现有父级

和你使用的这个sql脚本

  

INSERT INTO Textuals(Content,ParentId)VALUES(&#34; Lorem Ipsum&#34;,42)

这是适合你的。

using (var context = new  DatabaseContext())
{
    var newTextual  = new Textuals { Number = 42, Content = "I iz kiddo" };
    context.Textuals.Attach(newTextual);
    context.SaveChanges();
}