Массовая вставка и дублирование записей с помощью LINQ to SQL

Существует ли «лучший способ» обработки массовых вставок (через LINQ), но с отбрасыванием записей, которые уже могут быть в таблице? Или мне придется либо сделать массовую вставку в таблицу импорта, а затем удалить дубликаты, либо вставлять по одной записи за раз?


26.08.2010 - РЕДАКТИРОВАТЬ №1:
Сейчас я смотрю на методы Intersect и Except. Я собираю данные из отдельных источников, преобразую их в список, хочу «сравнить» с целевой БД, а затем ВСТАВИТЬ только НОВЫЕ записи.

List<DTO.GatherACH> allACHes = new List<DTO.GatherACH>();
State.IState myState = null;
State.Factory factory = State.Factory.Instance;
foreach (DTO.Rule rule in Helpers.Config.Rules)
{
    myState = factory.CreateState(rule.StateName);
    List<DTO.GatherACH> stateACHes = myState.GatherACH();
    allACHes.AddRange(stateACHes);
}

List<Model.ACH> newRecords = new List<Model.ACH>();  // Create a disconnected "record set"...
foreach (DTO.GatherACH record in allACHes)
{
        var storeInfo = dbZach.StoreInfoes.Where(a => a.StoreCode == record.StoreCode && (a.TypeID == 2 || a.TypeID == 4)).FirstOrDefault();

        Model.ACH insertACH = new Model.ACH
        {
            StoreInfoID = storeInfo.ID,
            SourceDatabaseID = (byte)sourceDB.ID,
            LoanID = (long)record.LoanID,
            PaymentID = (long)record.PaymentID,
            LastName = record.LastName,
            FirstName = record.FirstName,
            MICR = record.MICR,
            Amount = (decimal)record.Amount,
            CheckDate = record.CheckDate
        };
        newRecords.Add(insertACH);
}

Приведенный выше код создает список newRecords. Теперь я пытаюсь получить записи из этого списка, которых нет в БД, сравнивая уникальный индекс с 3 полями:

AchExceptComparer myComparer = new AchExceptComparer();
var validRecords = dbZach.ACHes.Intersect(newRecords, myComparer).ToList();

Компаратор выглядит так:

class AchExceptComparer : IEqualityComparer<Model.ACH>
{
    public bool Equals(Model.ACH x, Model.ACH y)
    {
        return (x.LoanID == y.LoanID && x.PaymentID == y.PaymentID && x.SourceDatabaseID == y.SourceDatabaseID);
    }

    public int GetHashCode(Model.ACH obj)
    {
        return base.GetHashCode();
    }
}

Однако я получаю эту ошибку:

LINQ to Entities не распознает метод «System.Linq.IQueryable1[MisterMoney.LARS.ZACH.Model.ACH] Intersect[ACH](System.Linq.IQueryable1[MisterMoney.LARS.ZACH.Model.ACH], System.Collections.Generic.IEnumerable1[MisterMoney.LARS.ZACH.Model.ACH], System.Collections.Generic.IEqualityComparer1[MisterMoney.LARS.ZACH.Model.ACH])», и этот метод не может быть преобразован в выражение хранилища.

Любые идеи? И да, это полностью соответствует исходному вопросу. :)


person Keith Barrows    schedule 26.08.2010    source источник
comment
Ага - ты прав. Я пишу на C#, а не на VB, и обычно у меня есть образцы кода с моим вопросом. Прости.   -  person Keith Barrows    schedule 26.08.2010


Ответы (3)


Я рекомендую вам просто написать SQL самостоятельно для вставки, я считаю, что это намного быстрее, и вы можете заставить его работать именно так, как вы хотите. Когда я сделал что-то подобное (только одноразовая программа), я просто использовал словарь для хранения уже вставленных идентификаторов, чтобы избежать дублирования.

Я считаю, что LINQ to SQL хорош для одной записи или небольшого набора, который выполняет всю свою жизнь в LINQ to SQL.

Или вы можете попробовать использовать массовую вставку SQL Server 2008 .

person Ted Ballou    schedule 26.08.2010

Вы не можете выполнять массовые вставки с помощью LINQ to SQL (я полагаю, вы имели в виду LINQ to SQL, когда говорили «LINQ»). Однако, основываясь на том, что вы описываете, я бы рекомендовал проверить новый Оператор MERGE SQL Server 2008. Вставка, обновление и удаление данных с помощью MERGE

Еще один пример.

person Steve Michelotti    schedule 26.08.2010
comment
Спасибо за это. К сожалению, это не то направление, в котором мне нужно идти. Для прямого сценария импорта я бы с удовольствием использовал это. Я дополнил свой первоначальный вопрос, чтобы внести ясность (надеюсь) в то, что я пытаюсь сделать. - person Keith Barrows; 26.08.2010

Одна вещь, на которую следует обратить внимание, это если вы ставите в очередь более 2000 или около того записей без вызова SubmitChanges() - TSQL имеет ограничение на количество операторов за выполнение, поэтому вы не можете просто поставить в очередь каждую запись, а затем вызвать SubmitChanges() как это вызовет SqlException, вам нужно периодически очищать очередь, чтобы избежать этого.

person Moo    schedule 26.08.2010
comment
Очень хорошо знать. Мой крупнейший клиент импорта прямо сейчас сидит на 459 записях (в своей ленте). Когда я урезаю его, я в среднем делаю 5 ВСТАВОК, 10 ОБНОВЛЕНИЙ и 5 УДАЛЕНИЙ каждый день. Остальные не изменились, поэтому мне не нужно выполнять какие-либо действия с ними. - person Keith Barrows; 15.06.2011