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

After setting EntityState.Unchanged the entity properties are lost

我有一个 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 属性 是从视图中的下拉列表中设置的。 在 post 上的控制器中,只设置了书的 Id。 告诉Entity Framework,只加学生,不加 参考书,我将书的 EntityState 设置为 Unchanged 作为 描述 here

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

我的控制器(简体):

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)
    ...
}

你应该查询 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();

问题是,实体框架 DbContext 缓存了实体。

With lazy loading, you simply need to make some reference to the related data and the Entity Framework will check to see whether it’s been loaded into memory. If not, the Entity Framework will create and execute a query behind the scenes, populating the related data.

By default, Visual Studio will define newly created models to set LazyLoadingEnabled to true.

(来自 MSDN

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

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

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

我想,这解决了问题,但我不确定 GuruStron 的回答是否使用了更好的模式。