2013-03-28 42 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