我的简化域模型看起来像这样:
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管理查找和持久性的最佳解决方案是什么?
你对自己的经历有任何建议吗?
答案 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,那么第二种方法可能更有意义。