LINQ to SQL insert-if-non-exist

我想知道如果在表中不存在记录,是否有更简单的方法来插入记录。 我还在尝试构建我的LINQ to SQL技能。

这就是我所拥有的,但似乎应该有一种更简单的方法。

public static TEntity InsertIfNotExists ( DataContext db, Table table, Func where, TEntity record ) where TEntity : class { TEntity existing = table.SingleOrDefault(where); if (existing != null) { return existing; } else { table.InsertOnSubmit(record); // Can't use table.Context.SubmitChanges() // 'cause it's read-only db.SubmitChanges(); } return record; } 

 public static void InsertIfNotExists (this Table table, TEntity entity, Expression> predicate) where TEntity : class { if (!table.Any(predicate)) { table.InsertOnSubmit(record); table.Context.SubmitChanges(); } } table.InsertIfNotExists(entity, e=>e.BooleanProperty); 

正如其他人所指出的那样, if (!Any()) { InsertOnSubmit(); } 解决方案都有竞争条件。 如果你走这条路线,当你调用SubmitChanges ,你必须考虑到a)可以为重复插入引发SqlException ,或者b)你可能在表中有重复的记录。

幸运的是,我们可以通过强制执行唯一性来使用数据库来避免竞争条件。 以下代码假定表上存在主键或唯一约束以防止插入重复记录。

 using (var db = new DataContext()) { // Add the new (possibly duplicate) record to the data context here. try { db.SubmitChanges(); } catch (SqlException ex) { const int violationOfPrimaryKeyContraint = 2627; const int violationOfUniqueConstraint = 2601; var duplicateRecordExceptionNumbers = new [] { violationOfPrimaryKeyContraint, violationOfUniqueConstraint }; if (!duplicateRecordExceptionNumbers.Contains(ex.Number)) { throw; } } } 

现在……如果必须在具有其他数据库更新的批处理事务中执行插入,事情会变得更加复杂。

同意marxidad的回答 ,但请参阅注释1。

注1:恕我直言,在辅助方法中调用db.SubmitChanges()是不明智的,因为你可能会破坏上下文事务。 这意味着如果在多个实体的复杂更新过程中调用InsertIfNotExists ,则不是一次保存更改,而是按步骤保存更改。

注意2: InsertIfNotExists方法是一种非常通用的方法,适用于任何场景。 如果您只想区分从数据库加载的实体与从代码创建的实体,您可以使用Entity类的部分方法OnLoaded ,如下所示:

 public partial class MyEntity { public bool IsLoaded { get; private set; } partial void OnLoaded() { IsLoaded = true; } } 

鉴于(和注释1),然后InsertIfNotExistsfunction减少到以下:

 if (!record.IsLoaded) db.InsertOnSubmit(record); 

马克答案的小修改:

如果您只关心通过其主键检查实体是否存在,Marke的答案可以像这样使用:

 public static void InsertIfNotExists (this Table table , TEntity entity ) where TEntity : class { if (!table.Contains(entity)) { table.InsertOnSubmit(entity); } }