Должен ли я проверять, существует ли строка перед удалением?

Я использую Mssql в качестве базы данных и EF4 в качестве ORM/DAL.
Мой вопрос касается следующего кода:

public static void DeleteBuilding(int buildingId, int countryId)
{
    PlayerBuilding playerBuilding = new PlayerBuilding()
    {
        CountryID = countryId,
        BuildingID = buildingId
    };
    Entities.PlayerBuildings.Attach(playerBuilding);
    Entities.PlayerBuildings.DeleteObject(playerBuilding);
    Entities.SaveChanges();
}

Если строка существует, это работает очень хорошо, если нет, я получаю исключение (оператор обновления, вставки или удаления хранилища затронул непредвиденное количество строк (0). Объекты могли быть изменены или удалено после загрузки сущностей. Обновить записи ObjectStateManager.)
Должен ли я выполнить обход базы данных, чтобы проверить, существует ли такая строка:

public static void DeleteBuilding(int buildingId, int countryId)
{
    PlayerBuilding playerBuilding = (from p in Entities.PlayerBuildings
                                     where p.BuildingID == buildingId && p.CountryID == countryId
                                     select p).FirstOrDefault();
    if (playerBuilding != null)
    {
        Entities.PlayerBuildings.DeleteObject(playerBuilding);
        Entities.SaveChanges();
    }
}

Я думаю, что в этом дополнительном обходе нет необходимости, потому что без EF, с простым SQL, я мог бы просто удалить строку с помощью одной команды DELETE.

Что было бы лучшей практикой?


person Adir    schedule 15.12.2010    source источник


Ответы (1)


Эта ошибка является побочным эффектом оптимистического параллелизма в Entity Framework.

По сути, кто-то другой мог удалить запись между тем, как вы ее извлекли. Или, может быть, вы что-то сделали с сущностью до этого кода.

Попробуйте запустить его в изолированной среде (например, в модульном тесте), чтобы увидеть, возникает ли проблема.

Да, вы можете перестраховаться и снова получить запись или использовать ObjectContext.Refresh:

public static void DeleteBuilding(int buildingId, int countryId)
{
    PlayerBuilding playerBuilding = new PlayerBuilding()
    {
        CountryID = countryId,
        BuildingID = buildingId
    };

    try
    {
       Entities.PlayerBuildings.Attach(playerBuilding);
       Entities.PlayerBuildings.DeleteObject(playerBuilding);
       Entities.SaveChanges();
    }
    catch (OptimisticConcurrencyException)
    {
       Entities.Refresh(RefreshMode.ClientWins, playerBuilding);
       Entities.SaveChanges();
    }
}

Кстати, может быть, это потому, что ваш метод статический? Как вы создаете свой контекст? Надеюсь, вы не используете синглтон. :(

Существует отличная статья об оптимистичном параллелизме EF здесь, где более подробно объясняется, почему вы получаете эту ошибку , и какие шаги можно предпринять, чтобы противостоять этому.

person RPM1984    schedule 15.12.2010
comment
спасибо за комментарий RPM, но это не оптимистичная проблема параллелизма. Я работаю на локальном компьютере разработчика, пробовал не статический метод, это тоже не проблема. Контекст создается с помощью этого метода: dotnetslackers.com/articles/ado_net/. используя обычный способ создания экземпляра контекста, ничего не меняя. - person Adir; 16.12.2010
comment
Взгляните на статью - ошибка в той статье точно такая же, как и у вас. Вы пытались запустить приведенный выше код в модульном тесте (изолированном)? Кроме того, каким образом в этой статье вы создаете экземпляр контекста? (в этой статье есть несколько методов) - person RPM1984; 16.12.2010
comment
Я использовал метод UnitOfWorkScope, но это не проблема. Даже если я создаю контекст, используя старый способ (MyContext context = new MyContext()), та же ошибка продолжает отображаться. Я не думаю, что это связано с параллелизмом, ошибка отображается, потому что я пытаюсь удалить объект, который не существует в контексте. - person Adir; 17.12.2010
comment
Хорошо. Вы пробовали метод обновления выше в моем ответе? Кстати, стоит ли вообще вызывать этот метод, если вы знаете, что объект не существует? - person RPM1984; 17.12.2010