在MVC2中管理查找并使用Nhibernate持久化对象

时间:2011-02-08 00:42:29

标签: asp.net-mvc nhibernate dns

我的简化域模型看起来像这样:

public abstract class Entity<IdK> 
{
    public virtual IdK Code { get; protected set; }
}

public class Contact : Entity
{
    public virtual string Name { get; set; }
    public virtual Company Company { get; set; }
}

public class Company : Entity
{
    public virtual string Name { get; set; }
}

我定义了一个viewmodel:

public ContactViewModel()
    {
            public Guid Code { get; set; }
            public int Version { get; set; }

            public string Name { get; set; }
            public string Company { get; set; }

            public List<SelectListItem> Companies { get; set; }
    }

在视图中管理我的联系人。
由于我希望用户能够从公司列表中进行选择,因此我添加了一个SelectedListItem列表,该列表将在我的视图中呈现,如下所示:

<%=Html.ListBoxFor(m => m.Company, (List<System.Web.Mvc.SelectListItem>)Model.Companies)%>

现在,当用户提交我的表单时,我会在保存之前使用我的模型重新映射我的viewmodel 我填充我的Contact并使用ContactViewModel.Company的id创建一个类型为Company的对象,以与Contact类的属性相关联。
由于我不想从数据库中获取整个公司,我只需填写id。 但是,当我保持联系时,我得到一个例外:“not-null属性引用null或瞬态Domain.Contact.Company”
使用MVC + Nhibernate管理查找和持久性的最佳解决方案是什么? 你对自己的经历有任何建议吗?

1 个答案:

答案 0 :(得分:2)

不幸的是,通过NHibernate和查找,您不能只将ID属性分配给Company对象的新实例,然后将该Company对象分配给Contact。

一般来说,我会做的是在我的存储库中,假设您在保存联系人时无法更改公司信息,请执行以下操作:

public Contact Save(Contact contact)
{
     if(contact.Company.Id > 0)
        contact.Company = Session.Load<Company>(contact.Company.Id);

     Session.SaveOrUpdate(contact);
}

我通常会发现这允许您封装加载公司的逻辑,并且还允许您在一个会话中很好地保留它。

以这种方式使用Session.Load可以避免按照here

所描述的方式访问数据库

如果你不这样做,你基本上对NHibernate说的是你有一个公司对象你已经分配了一个ID,现在想要保存它所有属性设置为Null或空字符串值或什么,那不是你想要的。

或者,您可以创建一个保存特定的域对象,如下所示:

public abstract class Entity<IdK> 
{
    public virtual IdK Code { get; protected set; }
}

public class SavableContact : Entity
{
    public virtual string Name { get; set; }
    public virtual IdK CompanyId { get; set; }
}

它直接映射到数据库中的Contact表,这样当您保存此实体时,您只需从View模型中映射回CompanyId,NHibernate将只保存该值,而不关心公司对象。

这是一个找出最适合你的方法。我个人更喜欢第一个选项,因为额外的逻辑位有助于简化域模型,但是如果您正在创建和公开公共API,那么第二种方法可能更有意义。