我希望在具有Entity Framework的表中插入或更新行,具体取决于表中是否已存在主键(字符串)。
我使用以下代码来执行此操作:Insert or update pattern
private void InsertOrUpdate(ServiceMonitoring sm)
{
try
{
using (var context = new MyDBEntities())
{
context.Entry(sm).State = sm.serviceName == null ?
EntityState.Added :
EntityState.Modified;
context.SaveChanges();
}
log.Info("ServiceMonitoring updated");
}
catch (Exception ex)
{
log.Error("Error updating ServiceMonitoring");
log.Debug(ex.Message);
}
}
当行(例如serviceName =“MyService”)已经存在时,它正常工作。然后执行更新。但是如果该行不存在,INSERT将失败并收到以下错误消息:
存储更新,插入或删除语句会影响意外 行数(0)。自那以后,实体可能已被修改或删除 实体已加载。
非常感谢任何帮助!
答案 0 :(得分:3)
更新或插入模式与MSDN示例中的主键一起使用的原因是它被标记为Identity
字段。将实体添加到DbContext时,EF会将Id字段的默认值设置为0,并且数据库将在执行INSERT
时为该行分配唯一值。
您尝试错误地调整“更新或插入”模式以使用属性serviceName
,解决方案是使用您引用的MSDN文章提供的模式,或执行查询。 / p>
为了完整,为什么你的改编不起作用?
因为您传入ServiceMonitoring
对象并期望context.Entry(sm)
在数据库中查询正确的数据行。它不是先生。因此,在您的情况下,EntityState.Added
基本上是无法访问的代码。
private void InsertOrUpdate(ServiceMonitoring sm)
{
try
{
//this brand new DbContext instance has not queried your database, and is not tracking any objects!
using (var context = new MyDBEntities())
{
//if (sm.serviceName is null) <- should never be null, as it's the ServiceMonitoring object you are passing into the function.
//The DbContext.Entry() does not know whether or not this actually exists in the database, it only allows you to inform
//EF about the state of the object.
context.Entry(sm).State = sm.serviceName == null ? //<- Always false (unless you *really* want a serviceName to not have a name)
EntityState.Added : // <- code unreachable
EntityState.Modified; //This is where the exception occurs, your code is always generating an UPDATE statement.
//When the entry exists in the database, EF's generated UPDATE statement succeeds.
//When the entry does not exist, the UPDATE statement fails.
context.SaveChanges();
}
log.Info("ServiceMonitoring updated");
}
catch (Exception ex)
{
log.Error("Error updating ServiceMonitoring");
log.Debug(ex.Message);
}
}