设置EntityState.Unchanged后,实体属性将丢失

时间:2015-02-12 14:24:13

标签: c# asp.net-mvc entity-framework entity-framework-6

我有一个ASP.Net MVC项目,我在其中添加了一个查看学生实体 到我的Entity Framework 6存储库。

class Student
  public long Id { get; set; }
  public virtual Book Favorite { get; set; }

class Book
  public long Id { get; set; }
  public string Title { get; set; }

Favorite属性是从视图中的下拉列表设置的。 在帖子的控制器中,只设置了书籍的Id。 告诉实体框架,只添加学生,但不添加 在引用的书中,我将Book的EntityState设置为Unchanged as 描述here

保存更改后,我在数据库中有正确的学生记录,并且书记录保持不变,但是 每当我从我的存储库(而不是通过学生)查询该书时,我都会得到一本书实体 返回仅设置了Id并且Title和所有其他属性为null。

我的控制器(简化):

public ActionResult Create()
{
    StudentViewModel result = new StudentViewModel();
    result.BookList = new SelectList(DbContext.Books, "Id", "Name");
    return View(result);
}

[HttpPost]
public ActionResult Create(StudentViewModel viewModel)
{
    DbContext.Entry(viewModel.NewStudent.Favorite).State = EntityState.UnChanged);
    DbContext.Add(viewModel.NewStudent);
    DbContext.SaveChanges();

    Book missingProperties = 
        DbContext.Books.Single(book => book.Id == viewModel.NewStudent.Favorite.Id);
} 

我的观点(简化):

@using System.Linq
@model StudentViewModel
@using (Html.BeginForm())
{        
    ...
    @Html.TextBoxFor(model => model.NewStudent.Name)
    @Html.DropDownListFor(model => model.NewStudent.Favorite.Id, Model.BookList)
    ...
}

2 个答案:

答案 0 :(得分:1)

你应该在保存新学生之前查询Favorite数据库(并检查那里是否有一个,因为你不应该发生什么来自客户端=),这样可以将本书送到上下文中,所以你只需将它设置给学生:

Book book = DbContext.Books.Single(book => book.Id == viewModel.NewStudent.Favorite.Id);
if(book!=null)
{
    viewModel.NewStudent.Favorite = book;
}
else
{
    throw new Exception();
}
DbContext.Add(viewModel.NewStudent);
DbContext.SaveChanges();

答案 1 :(得分:1)

问题是,Entity Framwork DbContext缓存实体。

  

使用延迟加载,您只需要对相关数据进行一些引用,实体框架将检查它是否已加载到内存中。如果没有,实体框架将在幕后创建并执行查询,填充相关数据。

     

默认情况下,Visual Studio将定义新创建的模型以将LazyLoadingEnabled设置为true。

(来自MSDN

从db加载后,将不再为DbContext生命周期加载它。 EntityState.UnChanged仅阻止Entity Framework将实体存储回数据库。但是每当第二次从上下文中检索实体时,不会从数据库中获取正确的值,而是修改后的,现在也在缓存中。

还需要刷新修改后的实体。将它附加在DbContext中,然后重新加载它。

Book result = Attach(book);
Entry(book).Reload();

我认为,这回答了这个问题,但我不确定GuruStron的回答是否使用了更好的模式。