避免在EF中插入时出现密钥冲突

时间:2011-01-24 17:47:19

标签: c# sql-server entity-framework exception-handling primary-key

我正在使用Entity Framework 4和SQL Server 2008 R2。我有一种情况,我想插入一个主键字段可能匹配现有记录的记录。我希望用新数据静默更新现有记录,而不是引发错误。

我目前的实现是这样的:

// Calculate primary key fields.
DateTime endDate = periodTime.AddMinutes(periodMins);
int meterId = pipe.MeterId;

// Try to load a matching record.
ProfileDatum lpRec = context.ProfileData.FirstOrDefault(rec => rec.MeterId == meterId && rec.EndDate == endDate);
// If it could not be loaded, create a new one.
if (lpRec == null)
{
    lpRec = new ProfileDatum() {MeterId = meterId,
                                EndDate = endDate};

    // Save the object in the context.
    context.ProfileData.AddObject(lpRec);
}

// Fill lpRec.

这很有效,但在效率,可读性和优雅方面非常糟糕。

坚持实体框架和SQL Server 2008 R2,有没有办法像MySQL的“重复密钥更新”那样继续进行,就像每次创建新记录一样,并在有主键时更新数据库违反?或许还有其他一些优雅的方法?

效率很好,但在这种情况下是次要的;我很简单。能够很棒 写下如下,省略客户端检查:

// Assign primary key fields.
var lpRec = new ProfileDatum()
{
    MeterId = pipe.MeterId,
    EndDate = periodTime.AddMinutes(periodMins)
};

// Fill lpRec.

// Save the object in the context.
context.ProfileData.AddObject(lpRec);

提前感谢您提供任何帮助,即使我说现有的实施方式是最佳方式。

3 个答案:

答案 0 :(得分:2)

你能使用ObjectContext.GetObjectByKey / TryGetObjectByKey吗?

根据msdn帮助:http://msdn.microsoft.com/en-us/library/bb738728.aspx

TryGetObjectByKey将首先查看已加载对象的列表,如果对象不存在,它将尝试通过PK从商店加载它。如果加载失败(它不在db中),则TryGetObjectByKey将返回false(GetObjectByKey将抛出)


IEnumerable<KeyValuePair<string, object>> entityKeyValues =
  new KeyValuePair<string, object>[]
  {
    new KeyValuePair<string, object> ("MeterId", meterId);
  }

  EntityKey key = new EntityKey("YourContainerName.YourEntitySetName", entityKeyValues);
  object entity = null;
  if(context.TryGetObjectByKey(key, out entity))
  {
     //the entity exists either in memory, or in the db
  }
  else
  {
     // you need to insert a new one
  }

答案 1 :(得分:1)

就效率而言,让它在DB中发生将是你最好的选择。因此,您要做的是将密钥的StoreGeneratedPattern属性设置为None,然后将Insert和Update方法指向使用SQL Server的MERGE功能的DB中的存储过程,如下所述:http://msdn.microsoft.com/en-us/library/bb522522.aspx < / p>

这就是为了尽可能高效地完成你所要求的。

那说......我认为这是一个糟糕的设计。通过让重复密钥以静默方式回退到更新,您打开的安全性和数据完整性漏洞太多了。您的模型应该表达明确且明确的意图,并且您的消费代码应该适当地使用这些意图或捕获异常并适当地处理该情况。

答案 2 :(得分:0)

我个人认为您的代码非常简单易读。我认为它很好地描述了你想要做的事情,未来的程序员将会在他们看到它时理解你的数据模型是如何工作的。

如果遇到与此相关的显着效率问题,可以将数据库设置为在找不到值时自动插入值。但这往往会使你的模型表现得“神奇”,所以如果效率是次要的,我会保持你的代码或多或少(可能使用JMarsh的建议来提高你不必进行数据库往返的可能性) )。