面對「Customer 需 Fullname = Firstname + Lastname」的需求,直接添加屬性會導致模型膨脹與重複。本文演示 NHibernate 組件 功能,實現細粒度對象模型與單表映射的完美結合。
Name 值對象,複用邏輯,資料庫結構零變動<component> 將子對象屬性映射到父表欄位,支援嵌套組件、集合、關聯。關鍵屬性:
name:父類屬性名class:組件類全名insert/update:控制欄位是否參與 INSERT/UPDATE<property> 映射組件屬性到表欄位<parent> 提供組件到容器的反向引用<dynamic-component> 則允許 IDictionary 作為組件映射,鍵值對應屬性名。
namespace DomainModel.Entities
{
public class Name
{
public string Firstname { get; set; }
public string Lastname { get; set; }
public string Fullname => Firstname + " " + Lastname;
}
}
純粹的值對象,無標識符,無需實現介面,封裝格式化邏輯。
namespace DomainModel.Entities
{
public class Customer
{
public virtual int CustomerId { get; set; }
public virtual int Version { get; set; }
public virtual Name Name { get; set; } // 替代原 Firstname/Lastname
}
}
注意:組件屬性同樣需要 getter/setter,NHibernate 透過屬性存取實現持久化。
<class name="DomainModel.Entities.Customer,DomainModel" table="Customer">
<id name="CustomerId" column="CustomerId" type="Int32" unsaved-value="0">
<generator class="native" />
</id>
<version name="Version" column="Version" type="integer" unsaved-value="0"/>
<component name="Name" class="DomainModel.Entities.Name,DomainModel">
<property name="Firstname" column="Firstname" type="string" length="50"
unique-key="UC_CustomerName"/>
<property name="Lastname" column="Lastname" type="string" length="50"
unique-key="UC_CustomerName"/>
</component>
</class>
效果:資料表仍為 CustomerId, Version, Firstname, Lastname,零結構變更。
c.Name.Firstname// 查詢
public IList<Customer> ReturnFullName(string firstname, string lastname)
{
return _session.CreateQuery(
"from Customer c where c.Name.Firstname=:fn and c.Name.Lastname=:ln")
.SetString("fn", firstname)
.SetString("ln", lastname)
.List<Customer>();
}
// 新建
var customer = new Customer
{
Name = new Name { Firstname = "YJing", Lastname = "Lee" }
};
[Test]
public void ReturnFullNameTest()
{
IList<Customer> customers = _relation.ReturnFullName("YJing", "Lee");
foreach (Customer c in customers)
Assert.AreEqual("YJing Lee", c.Name.Fullname);
}
組件映射實現了對象模型豐富化與資料庫模型簡潔化的雙贏:
Name.Fullname)Name 組件這正是 NHibernate 超越 LINQ to SQL 的建模靈活性所在。下篇進入關係映射核心領域。