Entity Framework: вставка со столбцом идентификаторов завершается с ошибкой «иногда» с помощью OptimisticConcurrencyException - PullRequest
0 голосов
/ 11 ноября 2009

При разработке и обучении с помощью Entity Framework у меня возникает любопытная проблема со вставками, когда я запускаю тесты для одной сущности в моей модели. В частности, проблема заключается в том, что некоторые тесты выполняются вместе. Я объясню:

У меня есть одна сущность в моей модели, называемая "DtoCategoria", с 2 членами: id: Int32 и name: string, сопоставленные с одной таблицей, где id - это столбец идентификаторов. Это нормально и довольно просто.

У меня есть уровень доступа к данным для этого DTO, называемый CadCategoria, где я создал метод для вставки, например:

public class CadCategoria
{
    protected readonly CUENTASEntities bd = Singletons.bd;

    public bool add(EntityObject entity)
    {
        try
        {
            bd.AddObject(EntitySet, entity);
            return bd.SaveChanges() > 0;
        }
        catch (Exception e)
        {
            bd.Detach(entity);
            return false;
        }
    }

    // and some other methods... update, delete, etc.
}

и некоторые другие общие методы для обновлений и удалений. Я делю контекст по уровням в приложении с одноэлементным шаблоном, например так:

public class Singletons
{
    public static CUENTASEntities bd;

    static Singletons()
    {
        bd = new CUENTASEntities();
    }
}

С тех пор это выглядит хорошо. Но я создал несколько модульных тестов, чтобы проверить, все ли в порядке, и выглядит так:

[TestClass]
public class CadCategoriaTest
{
    private CadCategoria bd = new CadCategoria();    

    [TestMethod]
    public void addTest()
    {
        var catAdd = new DtoCategoria { name= "cat 1" };
        Assert.IsTrue(bd.add(catAdd));

        bd.delete(catAdd);
    }

    [TestMethod]
    public void deleteTest()
    {
        var catDel = new DtoCategoria { name= "cat 2" };
        bd.add(catDel);

        Assert.IsTrue(bd.delete(catDel));
        Assert.IsFalse(bd.delete(new DtoCategoria { name= "not exists", id = -1 }));
    }

    [TestMethod]
    public void updateTest()
    {
        var a = new DtoCategoria { name= "cat 3" };
        bd.add(a);
        a.nombre = "name modified";
        Assert.IsTrue(bd.update(a));

        var b = bd.get(-1);
        Assert.IsFalse(bd.update(b));

        bd.delete(a);
    }
}

и теперь прибывает странная вещь:

  • При запуске только теста обновления: тесты пройдены
  • При запуске обновления и добавления тестов: тесты пройдены
  • При запуске обновления и удаления тестов: обновление теста не выполнено и удаление пройдено!

Ошибка во 2-й строке теста: bd.add (a); это вызывает исключение OptimisticConcurrencyException в методе SaveChanges контекста.

Есть идеи, почему у меня есть параллельное исключение со вставкой со столбцом идентификаторов? И только в сочетании с методом удаления теста ?? Этого не происходит в сочетании с тестом добавления, который также выполняет операцию добавления?

Боюсь, что если это не удастся в тесте, это также, скорее всего, не получится в реальном приложении. Этого не происходит с другим DTO, у которого нет идентификатора столбца идентификации как PK.

Есть идеи? Большое спасибо !!!

Sergi

1 Ответ

0 голосов
/ 12 ноября 2009

Ну, думаю, я наконец нашел проблему. Это не имело ничего общего с паттерном Синглтона. Дело в том, что мой тест удаления пытается удалить объект, который не существует, просто чтобы проверить, возвращает ли метод значение false:

Assert.IsFalse(bd.delete(new DtoCategoria { name= "not exists", id = -1 }));

но в методе bd.delete я забыл отсоединить несуществующий объект от контекста, поэтому в следующий раз, когда я попытался сделать context.SaveChanges (), было трижды удалить еще раз неправильный объект, поэтому он снова возник OptimisticException, поскольку ни одна строка не была удалена.

Это мой метод bd.delete:

public bool delete(EntityObject entity)
    {
        try
        {
            if (entity.EntityKey == null)
                entity.EntityKey = bd.CreateEntityKey(EntitySet, entity);
            if (entity.EntityState == EntityState.Detached)
                bd.AttachTo(EntitySet, entity);
            bd.DeleteObject(entity);
            return bd.SaveChanges() > 0;
        }
        catch (Exception e)
        {
            bd.Detach(entity);
            return false;
        }
    }

Решением была команда bd.Detach(entity); в секции catch, чтобы сообщить контексту забыть об этой фиктивной сущности. Быстрый взгляд на профилировщик SQL дал мне ответ.

Вот почему порядок имеет значение: удалить, затем обновить, вызвало сбой обновления. Оставив delete последним, все работало нормально, потому что в контексте больше не было SaveChanges ().

Спасибо за терпение, @Craig, и извините за неудобства.

Серги.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...