C# 实体框架:将现有子POCO添加到新的父POCO,在DB中创建新的子POCO

C# 实体框架:将现有子POCO添加到新的父POCO,在DB中创建新的子POCO,c#,.net,entity-framework,C#,.net,Entity Framework,我想在断开连接(从上下文)模式下使用实体框架POCO。在我的场景中,我正在创建一个新的父对象,并希望将现有的子对象附加到它,然后将其保存到数据库中。 下面的代码在保存新的学生记录时不希望插入新的课程记录,而我希望现有的课程记录链接到新的学生记录 如何在实体框架中执行此操作,其中 可以断开对象与上下文的连接。(即,在一个上下文中查询,然后在另一个上下文中保存) 我不需要从数据库中重新查询子记录,以便在保存到数据库时将其附加到父记录。我真的想避免在内存中已经有db作为对象的情况下对它进行额外的访问

我想在断开连接(从上下文)模式下使用实体框架POCO。在我的场景中,我正在创建一个新的父对象,并希望将现有的子对象附加到它,然后将其保存到数据库中。
下面的代码在保存新的学生记录时不希望插入新的课程记录,而我希望现有的课程记录链接到新的学生记录

如何在实体框架中执行此操作,其中

  • 可以断开对象与上下文的连接。(即,在一个上下文中查询,然后在另一个上下文中保存)
  • 我不需要从数据库中重新查询子记录,以便在保存到数据库时将其附加到父记录。我真的想避免在内存中已经有db作为对象的情况下对它进行额外的访问
此页显示下面的代码所基于的数据库关系图


实体框架不允许跨上下文的关系


如果您将课程阅读和课程与学生的连接放在同一个using语句中,它就会起作用。

我相信实现这一点的方法很少。 您可以指定课程实体保持不变而不是添加,如下所示:

ctx.Entry(course).State = EntityState.Unchanged;
或指示您的上下文,说明您正在使用现有实体:

ctx.Courses.Attach(course);
更多信息请点击此处:

编辑

我的解决方案中有一些正在运行的示例,我验证了它们是否按预期工作。 在所有情况下,我们在数据库中都有Publisher记录,ID=2,Name=“Addison Wesley”(与示例无关,但只是为了更好地衡量)

方法1-设置实体状态

using (var context = new Context())
{
    var book = new Book();
    book.Name = "Service Design Patterns";
    book.Publisher = new Publisher() {Id = 2 }; // Only ID is required
    context.Entry(book.Publisher).State = EntityState.Unchanged;
    context.Books.Add(book);
    context.SaveChanges();
}
using (var context = new Context())
{
     var book = new Book();
     book.Name = "Service Design Patterns";
     book.PublisherId = 2; 
     context.Books.Add(book);
     context.SaveChanges();
}
方法2-使用附加方法

using (var context = new Context())
{
    var book = new Book();
    book.Name = "Service Design Patterns";                
    book.Publisher = new Publisher() { Id = 2 }; // Only ID is required
    context.Publishers.Attach(book.Publisher);
    context.Books.Add(book);
    context.SaveChanges();
}
方法3-设置外键值

using (var context = new Context())
{
    var book = new Book();
    book.Name = "Service Design Patterns";
    book.Publisher = new Publisher() {Id = 2 }; // Only ID is required
    context.Entry(book.Publisher).State = EntityState.Unchanged;
    context.Books.Add(book);
    context.SaveChanges();
}
using (var context = new Context())
{
     var book = new Book();
     book.Name = "Service Design Patterns";
     book.PublisherId = 2; 
     context.Books.Add(book);
     context.SaveChanges();
}
对于最后一种方法,我需要添加额外的属性PublisherId,它必须根据NavigationPropertyName+“Id”约定命名,以便EF自动拾取:

public int PublisherId { get; set; }
public Publisher Publisher { get; set; }

我首先在这里使用EF5代码,但它与POCO非常相似。

我还尝试了第二个选项,它对我有效。我确实喜欢父->子关系首先发生在对象级别并保存到db。也许我应该删除EF生成的实体之间的所有关系,然后自己手动控制它。

第二个选项d选项几乎可以工作,但我得到一个“对象无法附加,因为它已经在对象上下文中。”错误出现在“ctx.Students.AddObject(stud);“行。我想我不能在仍然做”stud.Courses.Add(course);“在此之前。我希望仍然使用stud对象中的课程集合。我手头没有测试它的解决方案,但尝试先附加它,然后将其添加到student。希望这样不会将其标记为“添加”“英孚。这不是很理想。我希望父->子关系首先发生在对象级别,因为它可能还没有准备好保存到db。也许我应该删除EF生成的实体之间的所有关系,然后自己手动控制它?我刚刚在运行应用程序时尝试了一些示例方法,我将添加这些方法,它们可能会澄清一些解决方案。@MakkyNZ-好的,它们被添加了