如何在EF4中提交之前更新新记录?

时间:2011-03-19 07:17:12

标签: asp.net-mvc entity-framework entity-framework-4 poco unit-of-work

我正在使用EF4 POCO和UnitOfWork /存储库模式与MVC 3.我试图了解如何修改要插入的新记录。

我的插入/更新服务方法看起来像这样(存储库通过IoC注入服务构造函数):

public void UpdateData(Guid id, int newValue)
{
    MyPoco poco = _repository.FirstOrDefault(p => p.Id = id);

    if (poco == null)
    {
        poco = new Poco 
        {
            //set properties
        };

        _repository.Add(poco);
    }

    poco.SomeFieldToUpdate = newValue;
}

我的更改通过我的UnitOfWork在我的控制器上的UseUnitOfWorkAttribute操作过滤器上保留:

void IResultFilter.OnResultExecuted(ResultExecutedContext filterContext)
{
    var unitOfWork = IoCFactory.Instance.CurrentContainer.Resolve<IUnitOfWork>();
    unitOfWork.Commit();
}

当然,如果只针对现有数据或新数据点击一次,这样可以正常工作。如果它已经存在,它在多次通过时工作正常。

但是如果表中不存在Guid值,那么如果多次调用它,它会尝试多次插入。

这就是我的困境。我理解为什么这不起作用,我只是不确定正确的解决方法。基本上,我需要以某种方式获取UnitOfWork中现有POCO的引用,并以某种方式更新它。但UnitOfWork在我的服务中没有提供(按设计) - 我甚至不确定我是否知道如何从UoW中提取实体并进行更新。

我是在做错了还是在这里忽略了一些简单的事情?或者我是如何设计这个的根本缺陷?我有一种感觉,我可能会比现在更努力。

提前致谢。

2 个答案:

答案 0 :(得分:2)

发生这种情况的原因是因为您的实体尚未保存,而您执行查询以获取它。查询将无法在数据库中找到它并正确返回null。

您不应该使用存储库/工作单元/ ObjectContex作为服务调用中未保存实体的内部存储。如果您需要它,您应该检查您的应用程序设计并重构它,因为可能有些错误。

无论如何,你可以从上下文中获取未保存的实体,但它不是很好的代码。您需要在存储库中使用特殊方法来按ID获取实体。您将使用它而不是调用FirstOrDefault。类似的东西:

public MyPoco GetById(Guid id)
{
    MyPoco enity = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added)
        .Where(e => e.Entity != null && e.Entity.GetType() == typeof(MyPoco)))
        .Select(e => (MyPoco)e.Entity)
        .Where(p => p.Id == id)
        .SingleOrDefault();

    if (entity == null)
    {
        entity = context.MyPocos.FirstOrDefault(p => p.Id == id);
    }
}

答案 1 :(得分:0)

您是否将传递给UpdateData的ID设置为新Poco对象上的键,如下所示:

poco = new Poco 
{
    Id = id;
    //set properties
};

如果是,您可以查询不是FirstOrDefault的对象,而是使用存储库方法中的TryGetObjectByKey

public Poco GetPocoByKey(Guid id)
{
    EntityKey key = new EntityKey("MyEntities.Pocos", "Id", id);
    object pocoObject;
    if (context.TryGetObjectByKey(key, out pocoObject))
        return (Poco)pocoObject;

    return null;
}

优点是TryGetObjectByKey如果可以找到具有指定键的对象,则首先查看ObjectContext。只有在没有的情况下,才会查询数据库。由于您在第一次找不到时将新Poco添加到上下文中,TryGetObjectByKey应该在您第二次使用相同键搜索对象时在上下文中找到它,即使它尚未保存到数据库中

编辑:此解决方案不起作用!

因为TryGetObjectByKey找不到ObjectContext中处于added状态的对象的密钥,即使密钥不是DB生成的密钥并且由应用程序提供,也不会找到密钥(请参阅下面的注释)