.net 实体框架:插入标识列失败";有时";带着乐观的心情

.net 实体框架:插入标识列失败";有时";带着乐观的心情,.net,entity-framework,exception,.net,Entity Framework,Exception,在使用实体框架进行开发和学习时,当我为模型中的一个实体运行测试时,我在插入方面遇到了一个奇怪的问题。具体来说,问题是在一起运行一些测试时。我会解释我自己: 我的模型中有一个名为“DtoCategoria”的实体,有两个成员:id:Int32和name:string,映射到一个表中,其中id是一个标识列。这很好,也很简单 我有一个用于此DTO的数据访问层,称为CadCategoria,我在其中创建了一个用于进行插入的方法,如: public class CadCategoria { pro

在使用实体框架进行开发和学习时,当我为模型中的一个实体运行测试时,我在插入方面遇到了一个奇怪的问题。具体来说,问题是在一起运行一些测试时。我会解释我自己:

我的模型中有一个名为“DtoCategoria”的实体,有两个成员: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);这会在上下文的SaveChanges方法中引发OptimisticConcurrencyException

知道为什么我有一个带有标识列的insert的并发异常吗??仅当与删除测试方法结合使用时??与add测试结合使用时不会发生这种情况,add测试也会执行“add”操作

我担心,如果这在测试中失败,那么在真正的应用程序中也可能失败。这不会发生在另一个没有标识列id作为PK的DTO上

有什么想法吗?非常感谢


塞尔吉

嗯,我想我终于找到了问题所在。这与单身模式无关。事实上,我的delete测试尝试删除不存在的对象,只是为了检查该方法是否返回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(实体)命令,告诉上下文忽略此模拟实体。快速浏览一下SQL分析器,我就知道了答案

这就是为什么顺序很重要:删除然后更新导致更新崩溃。保留delete作为最后一个,效果很好,因为上下文中不再有SaveChanges()

谢谢你的耐心,@Craig,很抱歉给你带来不便


Sergi。

将ObjectContext设置为单例几乎肯定会导致问题。我不确定它是否会导致这个问题,但我不会费心去解决这个问题,直到你摆脱单身,因为当你这样做的时候问题可能会消失。此外,使用异常几乎总是错误的,可能会掩盖实际问题。我继续测试,发现测试的运行顺序很重要:删除和更新失败,但更新和删除通过。。。。知道吗?我忘了说我正在开发一个windows应用程序,它是单线程的,并且测试运行时可能是多线程的?如果是这样,这可能是问题所在,因为关于MSDN:“ObjectContext类不是线程安全的。ObjectContext中的数据对象的完整性在多线程场景中无法保证。”这可能是原因吗?Thanx Craig,但Singleton对我来说运行良好,因为我每个实体有一个DAL类,共享上下文,因为实体与其他实体相互关联,并且具有多个上下文会导致应用程序失败,且不一致。不要使用多个上下文或单个上下文。相反,在应用程序中适当地管理上下文生命周期。你不能跳过这个!