2008-09-19 2 views
11

Я хотел бы знать, есть ли более простой способ вставить запись, если она еще не существует в таблице. Я все еще пытаюсь создать свои навыки LINQ to SQL.LINQ to SQL insert-if-none-

Вот что у меня есть, но кажется, что должен быть более простой способ.

public static TEntity InsertIfNotExists<TEntity> 
(
    DataContext db, 
    Table<TEntity> table, 
    Func<TEntity,bool> where, 
    TEntity record 
) 
    where TEntity : class 
{ 
    TEntity existing = table.SingleOrDefault<TEntity>(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; 
} 

ответ

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


table.InsertIfNotExists(entity, e=>e.BooleanProperty); 
+0

Что такое e => e.BooleanProperty? Объекты не имеют члена BooleanProperty. Я никогда не видел этого раньше ... – core 2008-09-19 18:00:21

+0

Хм, вы заметите, что в моем коде я сказал, что table.Context.SubmitChanges() не работает, потому что он доступен только для загрузки. Видимо, я допустил ошибку. – core 2008-09-19 18:19:16

4

Согласен с marxidad's answer, но примечание 1.

Примечание 1: ИМХО, это не разумно называть db.SubmitChanges() в вспомогательный метод, потому что вы можете разорвать сделку контекста. Это означает, что если вы вызываете InsertIfNotExists<TEntity> в середине сложного обновления нескольких объектов, вы сохраняете изменения не сразу, а по шагам.

Примечание 2: Метод InsertIfNotExists<TEntity> - очень общий метод, который работает для любого сценария. Если вы хотите просто различать объекты, которые были загружены из базы данных от организаций, которые были созданы из кода, вы можете использовать частичный метод OnLoaded класса сущностей, как это:

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

Учитывая, что (и примечание 1), то функциональность InsertIfNotExists сводится к следующему:

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

Небольшая модификация для ответа Марка:

Если вы заботитесь только о проверке, если объект существует по его первичным ключом, ответ MARKE может можно использовать следующим образом:

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

     } 
    } 
11

Как уже отмечалось, 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; 
     } 
    } 
} 

Теперь ... все становится справедливыми немного сложнее, если вы должны выполнить вставку в пакетных операциях с другими обновлениями баз данных.