2013-03-28 84 views
2

我有以下Domain Model(s)NHibernate的一對一的關係

public class WriteOffApprovalUser 
{ 
    public virtual string UserName { get; set; } 
    public virtual Employee Employee { get; set; } 
} 

public class Employee 
{ 
    public virtual string EmployeeID { get; set; } 
    public virtual string EmployeeStatusCode { get; set; } 
    public virtual string FirstName { get; set; } 
    public virtual string LastName { get; set; } 
    public virtual string PreferredName { get; set; } 
    public virtual string JobTitle { get; set; } 
    public virtual string Division { get; set; } 
    public virtual string Department { get; set; } 
    public virtual string Location { get; set; } 
    public virtual string City { get; set; } 
    public virtual string DeskLocation { get; set; } 
    public virtual string MailID { get; set; } 
    public virtual string Phone { get; set; } 
    public virtual string Fax { get; set; } 
    public virtual string SecCode { get; set; } 
    public virtual string UserId { get; set; } 
    public virtual string SupervisorID { get; set; } 
} 

這些都是我Fluent Mappings

public class WriteOffApprovalUserMap : ClassMap<WriteOffApprovalUser> 
{ 
    public WriteOffApprovalUserMap() 
    { 
     //Schema("LEGAL"); 
     Table("WRITEOFF_APPROVAL_USER"); 

     Id(x => x.UserName).Column("USER_NAME"); 

     HasOne(x => x.Employee).PropertyRef("UserId"); 

    } 
} 

public class EmployeeMap : ClassMap<Employee> 
{ 
    public EmployeeMap() 
    { 
     // Table Name 
     //Schema("ADP_FEED_OWNER"); 
     Table("ADP_EMPLOYEE"); 

     // Primary Key 
     Id(x => x.EmployeeID).Column("EMPLID"); 

     // Mappings 
     Map(x => x.UserId).Column("USER_ID"); 
     Map(x => x.FirstName).Column("FIRST_NAME"); 
     Map(x => x.LastName).Column("LAST_NAME"); 
     Map(x => x.PreferredName).Column("PREFERRED_NAME"); 
    } 
} 

這裏是我的查詢:

var results = new Repository<WriteOffApprovalUser>(session) 
        .Query() 
        .ToList(); 

這是SQL它正在生成,而我期待着加入。

select writeoffap0_.USER_NAME as USER1_1_ from WRITEOFF_APPROVAL_USER writeoffap0_ 
SELECT employee0_.EMPLID as EMPLID0_0_, employee0_.USER_ID as USER2_0_0_, employee0_.FIRST_NAME as FIRST3_0_0_, employee0_.LAST_NAME as LAST4_0_0_, employee0_.PREFERRED_NAME as PREFERRED5_0_0_ FROM ADP_EMPLOYEE employee0_ WHERE employee0_.EMPLID=:p0; 
SELECT employee0_.EMPLID as EMPLID0_0_, employee0_.USER_ID as USER2_0_0_, employee0_.FIRST_NAME as FIRST3_0_0_, employee0_.LAST_NAME as LAST4_0_0_, employee0_.PREFERRED_NAME as PREFERRED5_0_0_ FROM ADP_EMPLOYEE employee0_ WHERE employee0_.EMPLID=:p0; 
SELECT employee0_.EMPLID as EMPLID0_0_, employee0_.USER_ID as USER2_0_0_, employee0_.FIRST_NAME as FIRST3_0_0_, employee0_.LAST_NAME as LAST4_0_0_, employee0_.PREFERRED_NAME as PREFERRED5_0_0_ FROM ADP_EMPLOYEE employee0_ WHERE employee0_.EMPLID=:p0; 
SELECT employee0_.EMPLID as EMPLID0_0_, employee0_.USER_ID as USER2_0_0_, employee0_.FIRST_NAME as FIRST3_0_0_, employee0_.LAST_NAME as LAST4_0_0_, employee0_.PREFERRED_NAME as PREFERRED5_0_0_ FROM ADP_EMPLOYEE employee0_ WHERE employee0_.EMPLID=:p0; 

現在有數據庫中的四排,右數據回來了,但我不希望五個單獨的SQL語句來做到這一點。

回答

1

您需要急切地加載/獲取Employee實體,以避免您看到的行爲通常被稱爲SELECT N + 1問題。爲了做到這一點,你有兩個選擇:

選項1.在映射意義貪婪加載在查詢WriteOffApprovalUser實體,它將總是執行連接到Employee表。 注意:這可能聽起來像你想要的,但要謹慎,因爲你會迫使所有曾與這個實體一起工作的開發人員一直堅持這個設計決定,直到時間結束。你將不得不問自己,我是否會想要查詢WriteOffApprovalUser表並且而不是對Employee表執行JOIN。如果答案是肯定的,那麼不要在映射文件中強制加載。

要讓員工自動獲取,改變你的HasOne代碼映射到這個樣子:

HasOne(x => x.Employee).PropertyRef("UserId").Not.LazyLoad().Fetch.Join(); 

選項2查詢執行預先加載。我注意到你正在使用某種T模式的Repository,所以你可能需要修改它來處理急切的加載。使用NHibernate內置的LINQ Query<T>類的NHibernate.Linq命名空間看起來是這樣的典型預先加載:

var results = new session.Query<WriteOffApprovalUser>() 
        .Fetch(x => x.Employee) // This will tell NHibernate to perform a JOIN to the Employee table 
        .ToList(); 
+0

非常堅實的答案!謝謝! – Sam

+0

雖然有一個問題,爲什麼存在SELECT N + 1問題? – Sam

+0

我撒謊,另一個問題。如果我改變映射到這個'HasOne(x => x.Employee).ForeignKey(「USER_ID」)。Constrained();'那麼我只得到'WriteOffApprovalUser'直到我調用'Fetch(x => x。僱員)'在查詢中,但與'PropertyRef'我仍然遇到SELECT N + 1問題。 – Sam