我想用实体框架更新现有条目,这是我当前的代码:
[HttpPost]
public IActionResult Edit(Product product)
{
if (ModelState.IsValid)
{
var result = _productRepository.Query().FirstOrDefault(x => x.Id == product.Id);
if (result == null)
return RedirectToAction("Index", "Products");
_productRepository.Update(product);
//result = product;
_productRepository.Save();
return View("Edit", result);
}
我尝试了什么:
result = product;
似乎没有更新db中的行。
public void Update(T item)
{
_context.Entry(item).CurrentValues.SetValues(item);
}
似乎没有更新db中的行。
result.Title = product.Title
- 有效,但是我必须为每个字段执行此操作,是否有办法仅通过将值替换为另一个对象来更新行?
答案 0 :(得分:1)
修改强>
实际上,我意识到下面的代码不起作用,因为你已经跟踪了同一个实体,这是由这一行引起的:
var result = _productRepository.Query().FirstOrDefault(x => x.Id == product.Id);
因此,您需要删除该行,只需使用下面的Update方法将product对象作为参数,或者使用结果对象并根据产品类中的数据进行更新,然后保存:
result.Name = product.Name;
[...]
在这种情况下,您不需要致电_repository.update
,只需_repository.save
使用产品进行更新
假设您的Product
类是与您的Product
实体类属于同一个类的对象,您需要确保它被实体框架跟踪并将其标记为已修改,然后才可以保存:
为此,请按以下步骤修改更新方法:
public void Update(T item)
{
if (!_context.Set<T>().Local.Any(e => e == item))
{
_context.Set<T>().Attach(item);
}
_context.Entry(item).State = EntityState.Modified
}
然后保存它,它应该工作:
_productRepository.Update(product);
_productRepository.Save();
更好的方法?
您可以专门为视图创建一个模型类,然后根据需要检索和更新数据库实体模型,而不是在视图之间来回发送实体框架实体:
例如,如果您的Product数据库实体如下所示:
public class Product
{
public int Id { get; set; }
public string ProductName { get; set; }
public int InternalId { get; set; }
}
在您看来,您不需要/想要使用InternalId字段,因此您的网站程序集中的模型可能如下所示:
public class ProductModel
{
public int Id { get; set; }
public string ProductName { get; set; }
}
然后在您的控制器中,这将是您将使用的:
[HttpPost]
public IActionResult Edit(ProductModel product)
{
if (!ModelState.IsValid)
{
return View(product);
}
var dbProduct = _productRepository.Query().FirstOrDefault(x => x.Id == product.Id);
if (dbProduct == null)
{
//Product doesn't exist, create one, show an error page etc...
//In this case we go back to index
return RedirectToAction("Index", "Products");
}
//Now update the dbProduct using the data from your model
dbProduct.ProductName = product.ProductName;
如果你有很多字段,你不想手动执行此操作,有一些库会为你做这件事,例如,AutoMapper或我个人最喜欢的(更快,更容易使用)ValueInjecter
使用ValueInjecter,你会做这样的事情来自动分配所有公共属性
dbProduct.InjectFrom(product);
最后,只需拨打保存,这次您不需要更改状态,因为EF已经在跟踪您的实体:
_productRepository.Save();