我正在使用.net核心。
我的目标: 我希望
Edit
之后能够Creating
成为SalesOrder。
现在我可以创建和编辑。但它正在抛出错误
无法跟踪实体类型'SalesOrder'的实例,因为 另一个具有相同密钥的此类实例已经存在 跟踪。添加新实体时,对于大多数键类型都是唯一的 如果没有设置密钥,则将创建临时密钥值(即,如果密钥 属性被指定为其类型的默认值)。如果你是 明确设置新实体的关键值,确保不这样做 与现有实体或为其他实体生成的临时值发生冲突 新实体。附加现有实体时,请确保只有一个实体 具有给定键值的实体实例附加到上下文。
当我在创建后尝试编辑时。
我的保存()功能:
public class SalesOrdersController : Controller
{
private readonly ApplicationDbContext _dbContext;
public SalesOrdersController(ApplicationDbContext dbContext){
_dbContext = dbContext;
}
// ...other Controller actions
public JsonResult Save([FromBody]SalesOrderViewModel salesOrderViewModel)
{
SalesOrder salesOrder = new SalesOrder();
salesOrder.document_id = salesOrderViewModel.document_id;
salesOrder.customer = salesOrderViewModel.customer;
salesOrder.document_status_id = salesOrderViewModel.document_status_id;
...
salesOrder.object_state = salesOrderViewModel.object_state;
_dbContext.Entry(salesOrder).State = Helpers.ConvertState(salesOrder.object_state);
_dbContext.SaveChanges();
salesOrderViewModel.document_id = salesOrder.document_id;
salesOrderViewModel.object_state = ObjectState.Unchanged;
return Json(new { salesOrderViewModel });
}
}
根据请求更新状态的功能:
public static EntityState ConvertState(ObjectState objectState){
switch (objectState){
case ObjectState.Added:
return EntityState.Added;
case ObjectState.Modified:
return EntityState.Modified;
case ObjectState.Deleted:
return EntityState.Deleted;
default:
return EntityState.Unchanged;
}
}
我知道在创建后刷新实体状态是一个问题。我该如何解决该错误?
答案 0 :(得分:-1)
你说你明白了这个问题......所以解决办法是从数据库中获取原始实体并直接更新其属性,然后自行更新。我的意思是你需要做的是避免打电话
context.Update(entity);
其中entity是模型中的对象。
因此,一个解决方案将类似于以下内容,我同意它可能不是解决它的最佳方式。
假设您正在使用通用存储库(这比非通用存储库更难,因为您事先不知道字段)
public void Edit(TBusinessObject entity)
{
var originalEntity = context.Set<TBusinessObject>().AsNoTracking().FirstOrDefault(r => r.Id.Equals(entity.Id));
EntityEntry<TBusinessObject> original = context.Entry(originalEntity);
EntityEntry<TBusinessObject> client = context.Entry(entity);
foreach (var property in original.OriginalValues.Properties)
{
var dbMember = original.Member(property.Name);
var clientMember = client.Member(property.Name);
if(!property.IsPrimaryKey() && dbMember.CurrentValue != clientMember.CurrentValue && clientMember.CurrentValue!= null)
{
dbMember.CurrentValue = clientMember.CurrentValue;
dbMember.IsModified = true;
}
}
context.Update(originalEntity);
context.SaveChanges(true);
}
同样,这段代码可以进行优化,如果它不是通用存储库,那么它就会更简单,你知道字段的名称和类型。
更新1: 我发现EF.Core虽然还没有完全成熟EF6支持的所有功能。然而,它在某种程度上倾向于现代开发实践。您发布的示例都是关于使用EF.Core来实现传统的存储库心态。如果您切换到使用UnitOfWork或CQRS,您将不会遇到这些问题,一般情况下更新和CRUS等更改将变得前所未有。我将一个对象传递给上下文,并且上下文本身能够确定它属于哪个表以及如何处理它。因此,我建议您更改选择使用EF.Core
的方式尝试这个最简单的实现:
public void Commit()
{
using (var context = new ApplicationDbContext())
{
context.UpdateRange(Changed);
context.AddRange(Added);
context.RemoveRange(Deleted);
context.SaveChanges();
ClearAllChanges();
}
}
“更改,添加,删除”只是您可能会考虑使用AsynchronousBags
的列表