在資料庫的多對多關係中, 實現方法是通過一個額外的關聯表將兩個主表關聯起來,關聯表中只儲存兩個主表的主健,顯然, 主表與關聯表是一對多的關係. 這樣兩個主表就通過這個關聯表構成了一個多對多的關係.
典型的例子就是使用者和許可權了, 每個使用者可以有多個許可權, 而每個許可權也可以分配給多個使用者. 通過一個使用者權限表就可以實現這樣的要求.
因為關聯表並沒有其它任何資訊, 所以在NH中它不能算是一個持久對象, 沒必要像處理one-to-many的情況那樣.在NH中, 通過值集合映射來處理這種情況.
下面以使用者/許可權為例再看看實際的處理情況.
測試代碼
[Test]
public void TestUserPermission() {
User u = new User();
u.Name = "test name";
u.Password = "test password";
u.AddPermission( 10 );
session.Save(u);
session.Close();
User u2 = session.Load( typeof(User), u.UserId );
Assertion.AssertNotNull( "add permission fail!", u2.Permissions[ 10 ] );
u2.AddPermission( 20 );
u2.RemovePermission( 10 );
session.Save(u2);
session.Close();
User u3 = session.Load( typeof(User), u.UserId );
Assertion.AssertNull( "remove permission fail!", u3.Permission[ 10 ] );
Assertion.AssertNotNull( "add permission fail!", u3.Permission[ 20 ] );
}
以上測試代碼中session的相關操作請查看相關文檔。
在這裡給User類定義了兩個操作許可權的方法: AddPermission和RemovePermission.
類定義
public class User {
public User() {
}
public void AddPermission( int permissionId ) {
permissions[ permissionId ] = dummyObject;
}
public void RemovePermission( int permissionId ) {
permissions.Remove( permissionId );
}
#region O/R Mapping Fields.
private int userId;
public int UserId
{
get { return userId; }
set { userId = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private string password;
public string Password
{
get { return password; }
set { password = value; }
}
private IDictionary permissions = new Hashtable();
public IDictionary Permissions
{
get { return permissions; }
set { permissions = value; }
}
#endregion
private readonly object dummyObject = new object();
}
在User類中,定義了一個Permissions集合用來儲存使用者的許可權. 因為使用了IDictionary, 所以也定義了一個啞對象.
對應檔
<class name="User, AssemblyName " table="Users">
<id name="UserId" column="user_id" type="Int32" unsaved-value="0">
<generator class="identity"/>
</id>
<property name="Name" column="name" type="String"/>
<property name="Password" column="password" type="String"/>
<set name="Permissions" table="UserPermissions">
<key column="user_id"/>
<element column="permission_id" type="Int32"/>
</set>
</class>
在set定義中, 指定值集合的名稱,以及關聯表的名稱, 再指定key值, 也即在關聯表的健, 一般是主健.
element元素指定產生值集合的列和類型.
值集合的開銷遠小於對象集合的開銷, 在有些時候, 可以考慮將one-to-many簡化為集集合, 這樣我們只取得many的id值, 在需要訪問many對象時再載入, 這也算是消極式載入的一個變相實現吧.