首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

NBearV3 ORM 實體關係設計速查手冊

     編輯:關於.NET

版本資訊

版本:1.2 [2006-11-13]

簡介

本手冊提供 NBearV3 所支援之所有實體關係設計的完整參考,涵蓋一對一、一對多、多對多關聯以及自關聯的正向與反向引用等各種情況的設計方法。

重要說明

  • 註 1:本手冊不討論繼承關係,因為繼承關係自然映射到實體介面的繼承,無需額外討論。
  • 註 2:所有演示中的關聯均包含正向與反向的可讀寫引用。實際專案中不一定需要雙向引用,可僅在單向包含引用,或一方只包含外鍵 ID,也可設為唯讀引用。雙向引用時,絕對不能同時將正向與反向的 LazyLoad 設為 false。
  • 註 3:關聯中的引用屬性可依需求加上 ContainedAttribute 以實現級聯更新/刪除。演示代碼未包含此屬性,實務上請酌情添加,但正反向引用不可同時加上。
  • 註 4:建議先閱讀《NBearV3 Step by Step 教程——ORM 篇》以掌握基礎知識。

程式碼範例來源

本手冊所有類圖與代碼收錄於 NBearV3 最新原始碼套件(sf.net 下載)中的 tutorials\Entity_Relation_Manual 目錄,遇到疑問可直接參考該代碼。


一、一對一主鍵關聯

一對一主鍵關聯類圖

分析:一對一主鍵關聯指兩個實體透過相同主鍵值關聯。典型範例為 User 與 UserProfile。UserProfile 不能脫離擁有相同主鍵的 User 存在。實際上,UserProfile.UserID 同時是其主鍵 (PK) 又是關聯到 User 的外鍵 (FK),且應對 User.ID 有引用完整性約束。

程式碼實作

public interface User : Entity
{
    [PrimaryKey]
    Guid ID { get; set; }
    string Name { get; set; }

    [PkQuery(LazyLoad=true)]
    UserProfile Profile { get; set; }
}

public interface UserProfile : Entity
{
    [PrimaryKey]
    [FriendKey(typeof(User))]
    Guid UserID { get; set; }
    string Content { get; set; }

    [PkReverseQuery(LazyLoad = true)]
    User User { get; set; }
}

二、一對一外鍵關聯

一對一外鍵關聯類圖

分析:一對一外鍵關聯指一個實體透過自身的一個外鍵關聯另一實體。在關聯語義與資料庫映射上與一對多(外鍵)關聯非常相似,因此一對多中 FkQuery 與 FkReverseQuery 的解釋同樣適用。典型範例同為 User 與 UserProfile,不同處在於此時 UserProfile.ID 與 User.ID 無關,分別作為各自主鍵;UserProfile.UserID 為外鍵關聯到 User,並應對 User.ID 有引用完整性約束。

程式碼實作

public interface User : Entity
{
    [PrimaryKey]
    Guid ID { get; set; }
    string Name { get; set; }

    [FkQuery("User", LazyLoad=true)]
    UserProfile Profile { get; set; }
}

public interface UserProfile : Entity
{
    [PrimaryKey]
    Guid ID { get; set; }
    string Content { get; set; }

    [FkReverseQuery(LazyLoad=true)]
    User User { get; set; }
}

註:標記在 User.Profile 上的 FkQuery 建構函式需一個參數,指定該外鍵查詢引用屬性對應的反向引用屬性為 UserProfile 實體的 User 屬性。


三、一對一自關聯

一對一自關聯類圖

分析:一對一自關聯類似一對一外鍵關聯,差別僅在於關聯雙方為同一實體。

程式碼實作

public interface Person : Entity
{
    [PrimaryKey]
    Guid ID { get; set; }
    string Name { get; set; }

    [FkReverseQuery(LazyLoad=true)]
    [MappingName("MateID")]
    [SerializationIgnore]
    Person Mate { get; set; }
}

註 1:一對一自關聯可用單一屬性表示雙向引用,也可用正反兩個屬性。但必須至少將其中一個引用設為 LazyLoad=true,且至少一個設為 SerializationIgnore,以避免序列化死循環。

註 2:MappingName("MateID") 為可選屬性,顯式指定資料庫對應欄位名稱。若不指定,預設為「屬性名_主鍵名」(如 Mate_ID)。本手冊其他關聯屬性的 MappingName 含義相同。


四、一對多關聯

一對多關聯類圖

分析:一對多關聯指一個實體透過被關聯實體的一個外鍵關聯多個被關聯實體集合。下圖示例表示 Team 可包含多個 User。

程式碼實作(雙向引用)

public interface Team : Entity
{
    [PrimaryKey]
    Guid ID { get; set; }
    string Name { get; set; }

    [FkQuery("Team", OrderBy="{Name} DESC", Contained=true, LazyLoad=true)]
    User[] Users { get; set; }
}

public interface User : Entity
{
    [PrimaryKey]
    Guid ID { get; set; }
    string Name { get; set; }

    [FkReverseQuery(LazyLoad=true)]
    Team Team { get; set; }
}

註 1:FkQuery 的 OrderBy 屬性可指定類 SQL 語法的排序規則,用於對關聯對象集合排序。

註 2:FkQuery 建構函式第一個參數指定被關聯實體中的關聯屬性。可為 FkReverseQuery 屬性(雙向引用),也可為外鍵屬性(單向引用)。若只要單向引用,可將 User.Team 改為簡單外鍵屬性,並修改建構函式參數為該外鍵屬性名稱:

public interface Team : Entity
{
    [PrimaryKey]
    Guid ID { get; set; }
    string Name { get; set; }

    [FkQuery("TeamID", Contained=true, LazyLoad=true)]
    User[] Users { get; set; }
}

public interface User : Entity
{
    [PrimaryKey]
    Guid ID { get; set; }
    string Name { get; set; }

    [FriendKey(typeof(Team))]
    Guid TeamID { get; set; }
}

註 3:FkQuery 可設 Contained 屬性,使被關聯對象隨主對象更新時自動級聯更新。


五、一對多自關聯

一對多自關聯類圖

分析:一對多自關聯的定義方法與一般一對多關聯完全相同。

程式碼實作

public interface Group : Entity
{
    [PrimaryKey]
    Guid ID { get; set; }
    string Name { get; set; }

    [FkReverseQuery(LazyLoad=true)]
    [MappingName("ParentID")]
    Group ParentGroup { get; set; }

    [FkQuery("ParentGroup", LazyLoad=true)]
    [SerializationIgnore]
    Group[] ChildGroups { get; set; }
}

註:同樣必須至少將一個引用設為 LazyLoad=true,且至少一個設為 SerializationIgnore,避免序列化死循環。


六、多對多關聯

多對多關聯類圖

分析:多對多關聯指一實體可關聯另一實體的多個對象,反之亦然。以 Group 與 User 為例:一個群組可有多個用戶,一用戶也可屬於多個群組。映射到資料庫時,必須有一個獨立的關聯表,對應此處的 UserGroup 關聯實體。

程式碼實作

public interface Group : Entity
{
    [PrimaryKey]
    Guid ID { get; set; }
    string Name { get; set; }

    [ManyToManyQuery(typeof(UserGroup), LazyLoad=true)]
    User[] Users { get; set; }
}

public interface User : Entity
{
    [PrimaryKey]
    Guid ID { get; set; }
    string Name { get; set; }

    [ManyToManyQuery(typeof(UserGroup), LazyLoad = true)]
    Group[] Groups { get; set; }
}

[Relation]
public interface UserGroup : Entity
{
    [RelationKey(typeof(User))]
    Guid UserID { get; set; }

    [RelationKey(typeof(Group))]
    Guid GroupID { get; set; }
}

註 1:多對多關聯實體必須以 RelationAttribute 標記。其關聯雙方的屬性需用 RelationKeyAttribute 標記,建構函式參數(如 typeof(User)、typeof(Group))表示該屬性用於關聯到哪個實體。

註 2:在 Group 與 User 中,Users 與 Groups 屬性必須設 ManyToManyQueryAttribute,並以關聯實體 UserGroup 的類型作為建構函式參數。


七、自定義關聯

自定義關聯類圖

分析:除常規關聯外,NBear 尚支援 CustomQuery 設定自定義查詢關聯屬性。它可在一般一對一、一對多、多對多查詢基礎上附加額外約束條件。不同處在於:自定義查詢關聯的對象不會被級聯更新。這些條件通常較簡單,但靈活運用可大幅減少業務類代碼。

下例包含三個實體:Team、Group、User。Team 與 User 為一對多,User 與 Group 為多對多,User 另包含數個 CustomQuery 屬性:

程式碼實作

public interface Team : Entity
{
    [PrimaryKey]
    Guid ID { get; set; }
    string Name { get; set; }
    bool IsAvailable { get; set; }

    [FkQuery("Team", OrderBy = "{Name} DESC", Contained = true, LazyLoad = true)]
    User[] Users { get; set; }
}

public interface User : Entity
{
    [PrimaryKey]
    Guid ID { get; set; }
    string Name { get; set; }

    [ManyToManyQuery(typeof(UserGroup), LazyLoad = true)]
    Group[] Groups { get; set; }

    [FkReverseQuery(LazyLoad = true)]
    Team Team { get; set; }

    [CustomQuery("{LeaderName} = @Name AND {IsPublic} = 1")]
    Group[] PublicLeadingGroups { get; set; }

    [CustomQuery("{IsAvailable} = 1", OrderBy="{Name}")]
    Team AvailableTeams { get; set; }

    [CustomQuery("{IsHidden} = 1", RelationType=typeof(UserGroup), OrderBy="{ID} DESC")]
    Group[] DivingGroups { get; set; }
}

public interface Group : Entity
{
    [PrimaryKey]
    Guid ID { get; set; }
    string Name { get; set; }
    string LeaderName { get; set; }
    bool IsPublic { get; set; }

    [ManyToManyQuery(typeof(UserGroup), LazyLoad = true)]
    User[] Users { get; set; }
}

[Relation]
public interface UserGroup : Entity
{
    [RelationKey(typeof(User))]
    Guid UserID { get; set; }

    [RelationKey(typeof(Group))]
    Guid GroupID { get; set; }

    bool IsHidden { get; set; }
}

說明:

  • User.PublicLeadingGroups:公開且 LeaderName 為該用戶名稱的所有群組。
  • User.AvailableTeams:系統中所有 IsAvailable 為真團隊。
  • User.DivingGroups:用戶所屬但處於「潛水」狀態(對群組其他成員不可見)的群組。其查詢條件 {IsHidden} = 1 中的 IsHidden 來自關聯實體 UserGroup,故需指定 RelationType=typeof(UserGroup)。亦可用 OrderBy 指定預設排序。

正文結束

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved