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

时间:2013-01-13 20:31:30

标签: c# .net entity-framework

我想在断开连接(来自上下文)模式下使用Entity Framework POCO。在我的场景中,我正在创建一个新的Parent对象,并希望将现有的子对象附加到它,然后将其保存到db。 保存新的学生记录时,下面的代码会不合期望地插入新的课程记录,而我希望现有的课程记录链接到新的学生记录。

我如何在实体框架中执行此操作......

  • 可以将对象与上下文断开连接。 (即在一个上下文中查询,然后在不同的上下文中保存)
  • 我不需要从DB重新查询子记录,所以当我保存到db时,我可以将它附加到父级。当我已经将它作为内存中的对象时,我真的想避免额外访问数据库。

此页面显示了以下代码基于http://entityframeworktutorial.net/EF4_EnvSetup.aspx#.UPMZ4m-UN9Y

的数据库图表
class Program
{
    static void Main(string[] args)
    {

        //get existing course from db as disconnected object
        var course = Program.getCourse();

        //create new student
        var stud = new Student();
        stud.StudentName = "bob";

        //assign existing course to the student
        stud.Courses.Add(course);

        //save student to db
        using (SchoolDBEntities ctx = new SchoolDBEntities())
        {
            ctx.Students.AddObject(stud);
            ctx.SaveChanges();
        }
    }

    static Course getCourse()
    {
        Course returnCourse = null;

        using (var ctx = new SchoolDBEntities())
        {
            ctx.ContextOptions.LazyLoadingEnabled = false;
            returnCourse = (from s in ctx.Courses
                            select s).SingleOrDefault();
        }

        return returnCourse;
    }
}

3 个答案:

答案 0 :(得分:17)

我相信实现这一目标的方法很少。 您可以指定课程实体不变,而不是添加,沿着以下几行:

ctx.Entry(course).State = EntityState.Unchanged;

或者指导您的上下文,即您正在使用现有实体:

ctx.Courses.Attach(course);

更多信息: http://msdn.microsoft.com/en-us/data/jj592676.aspx

修改

我的解决方案中有一些运行样本,我验证它们按预期工作。 在所有情况下,我们在数据库中都有发布者记录,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();
}

方法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.PublisherId = 2; 
     context.Books.Add(book);
     context.SaveChanges();
}

对于最后一种工作方法,我需要添加额外的属性PublisherId,它必须根据要自动获取EF的NavigationPropertyName +'Id'约定命名:

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

我在这里使用EF5 Code First,但它与POCO非常相似。

答案 1 :(得分:0)

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

如果您在相同的使用声明中放置课程阅读并将课程与学生联系起来,那就可以了。

答案 2 :(得分:0)

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