7

在我的 ASP.NET MVC 应用程序中,我将域模型与视图模型分开。
我在视图模型对象中转换我的实体,这样我就可以只用所需的数据“提供”我的视图(为此我使用了 valueinjecter)。
在保存过程中,我的控制器取回 viewmodel 对象,将其转换为域模型实体并尝试使用 SaveOrUpdate 将其持久化。我注意到,如果我尝试更新现有记录,Nhibernate 会将其视为新对象并强制插入,即使我的实体具有正确的 ID。
我之前没有加载(获取/加载)实体,因为我想避免再次重新映射所有字段。
有什么我做错了吗?实现这一目标的最佳方法是什么?

***** - 更新 - ***

我的控制器接收到一个用户(ViewModel),对其进行验证并尝试通过服务层将其保存为实体:

public ActionResult Edit(Guid id, Models.User User)
{
...
var user = new Domain.User();
user.InjectFrom(User);
user.SetId(id);

user = this._SecurityService.SaveUser(user);

}

这是服务:

public Domain.User SaveUser(Domain.User User)
        {
            bool Result = false;

            if (this._ValidationEngine.IsValid(User))
            {
                using (_UnitOfWork)
                {
                    if (User.Code != Guid.Empty)
                    {
                        var user = this._UserRepository.Load(User.Code);
                        user.InjectFrom(User);
                        User = this._UserRepository.Update(user);
                    }
                    else {
                        User = this._UserRepository.Save(User);
                    }
                    Result = _UnitOfWork.Commit();
                }
            }
            return (User);
        }

我担心我必须多次转换我的视图模型/实体。现在,当我尝试保存新用户时,我收到此消息:行已被另一个事务更新或删除(或未保存的值映射不正确)
这可能在某些方面与达林告诉我的有关。
有没有更好的方法来做我想做的事情?

更新

我注意到错误“行已更新或删除...”是由于我为我的映射定义了一个版本。我能理解的是我需要Id和与我要更新的实体匹配的版本。
我想了解其他人如何使用 DDD + ASP.NET MVC + NHibernate 来做这些事情???

解决方案

我所有的实体都定义了一个版本(我忘了说,对不起):

<version name="Version" type="System.Int32" unsaved-value="0">
   <column name="Version" not-null="true" />
</version>

正如 Ayende在这里解释的那样,Nhibernate 尝试使用如下查询更新我的实体:

UPDATE Table SET field1 = 'bla', Version = (y+1) WHERE id = x AND Version = y

where y should be the version of my entity. Since I wasn't populating my entity with a version, it would generate an exception StaleObjectException.
I've added a version field to my viewmodel. I save it in a hidden field of my view together with the id.
My controller now receives a viewmodel with an Id and a version. I inject these fields in my domain entity and let the repository save it (I don't reload my entity):

User = this._UserRepository.Update(user);

If I get a StaleObjectException exception it means that someone else has updated the DB row and I'll provide the user with some feedback.

4

2 回答 2

4

For SaveOrUpdate to work as expected you need to explicitly specify the unsaved-value attribute on your <id> mapping. So for example you would have:

<id unsaved-value="0" ...

and then issue a SaveOrUpdate call on a model which has the Id property assigned to a value different than 0 and it is going to UPDATE instead of INSERT. So to answer your question, no, you don't need to manually issue a SELECT before UPDATE. SaveOrUpdate should do this behind the scenes.

于 2011-01-26T12:53:11.913 回答
0

Since you already have an Id and, therefore, know this is an update, use session.Update instead of SaveOrUpdate.

于 2011-01-26T14:51:33.590 回答