EF4.1 DBContext: вставка / обновление в одной функции Save () без идентификатора PK - PullRequest
0 голосов
/ 19 сентября 2011

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

С EF4.1 и DBContext я хотел бы написать один метод "Сохранить", который использует улицу (входит в неприсоединенное состояние), проверяет, существует ли она уже в базе данных. Если это так, он выдает ОБНОВЛЕНИЕ, а если нет, то выдает ВСТАВКУ.

FYI, приложение, которое сохраняет эти улицы, читает их из текстового файла и сохраняет их (в этом файле несколько десятков тысяч этих "линий улиц").

На данный момент я придумал:

    public void Save(Street street)
    {
        var existingStreet = (
                                from s in streetContext.Streets
                                where s.PostalCode.Equals(street.PostalCode)
                                && s.StreetCode.Equals(street.StreetCode)
                                select s
                             ).FirstOrDefault();

        if (existingStreet != null)
            this.streetContext.Entry(street).State = System.Data.EntityState.Modified;
        else
            this.streetContext.Entry(street).State = System.Data.EntityState.Added;

        this.streetContext.SaveChanges();
    }

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

Не лучше ли было бы с точки зрения производительности попытаться вставить улицу (состояние = добавлено) и отследить любые нарушения ПК? Затем в блоке catch я могу изменить состояние на «измененное» и снова вызвать SaveChanges (). Или это не будет хорошей практикой?

Есть предложения?

Спасибо

Ответы [ 3 ]

1 голос
/ 30 сентября 2011

Спасибо за ответы, но ни один из них не был по-настоящему удовлетворительным, поэтому я провел дополнительное исследование и переписал метод, подобный этому, который удовлетворяет мои потребности.

ps: переименовал метод в Import (), потому что я считаю, что более подходящее имя для метода, который используется для (массового) импорта объектов из внешнего источника (как текстовый файл в моем случае)

ps2: Я знаю, что на самом деле не рекомендуется ловить исключение и позволять ему молча умирать, ничего не делая с ним, но мне не нужно ничего делать с ним в моем конкретном случае. Он просто служит способом узнать, что строка уже существует в базе данных.

public void Import(Street street)
{
        try
        {
            this.streetContext.Entry(street).State = System.Data.EntityState.Added;

            this.streetContext.SaveChanges();
        }
        catch (System.Data.Entity.Infrastructure.DbUpdateException dbUex)
        {
            this.streetContext.Entry(street).State = System.Data.EntityState.Modified;

            this.streetContext.SaveChanges();
        }
        finally
        {
            ((IObjectContextAdapter)this.streetContext).ObjectContext.Detach(street);
        }
} 
1 голос
/ 19 сентября 2011

Выберите все улицы, затем создайте для каждого цикла, который сравнивает и изменяет состояния.После завершения цикла вызовите saveChanges.Таким образом, вы делаете всего несколько звонков в БД вместо нескольких тысяч

0 голосов
/ 19 сентября 2011

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

Если вам действительно нужно сделать это, используйте вместо этого этот код:

public void Save(Street street)
{
    string postalCode = street.PostalCode;
    string streetCode = steet.StreetCode;
    bool existingStreet = streetContext.Streets.Any(s =>
                            s.PostalCode == postalCode
                            && s.StreetCode = steetCode);

    if (existingStreet)
        streetContext.Entry(street).State = System.Data.EntityState.Modified;
    else
        streetContext.Entry(street).State = System.Data.EntityState.Added;

    streetContext.SaveChanges();
}

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

...