Вопрос

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

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

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;
}
Это было полезно?

Решение

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);

Другие советы

Как отмечали другие, if (!Any()) { InsertOnSubmit(); } все решения имеют состояние гонки.Если вы пойдете по этому маршруту, когда вы позвоните SubmitChanges, вы должны принять во внимание, что либо а) а SqlException может возникнуть из-за дублирующейся вставки, или б) в таблице могут быть повторяющиеся записи.

К счастью, мы можем использовать базу данных, чтобы избежать состояния гонки, обеспечив уникальность.В следующем коде предполагается, что в таблице существует первичный ключ или ограничение уникальности, чтобы предотвратить вставку повторяющихся записей.

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;
        }
    }
}

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

Согласен с ответ марксидада, но см. примечание 1.

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

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

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

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

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

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

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

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

        }
    }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top