NHibernate One-To-One Relationship

こ雲淡風輕ζ 提交于 2021-01-27 17:10:32

问题


I have the following Domain Model(s):

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; }
}

These are my 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");
    }
}

Here is my Query:

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

This is the SQL it is generating, and I was expecting a JOIN instead.

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;

Now there are four rows in the database, and the right data is coming back, but I would not expect five separate SQL statements to do this.


回答1:


You need to eager load/fetch the Employee entity to avoid the behavior that you are seeing which is often referred to as the SELECT N+1 problem. In order to do this you have two options:

Option 1. Eager load in the mapping meaning when you query the WriteOffApprovalUser entity, it will always perform a JOIN to the Employee table. Note: This may sound like what you want but be cautious as you will force all developers who ever work with this entity to be stuck with this design decision until the end of time. You'll have to ask yourself, would I ever want to query the WriteOffApprovalUser table and not perform a JOIN to the Employee table. If the answer is yes, then don't force the eager loading in the mapping file.

To have the Employee automatically fetched, change your HasOne code in the mapping to look something like this:

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

Option 2. Perform the eager loading in the query. I noticed that you are using some kind of Repository of T pattern so you may have to modify it to handle eager loading. Typical eager loading using NHibernate's built in LINQ Query<T> class in the NHibernate.Linq namespace looks something like this:

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


来源:https://stackoverflow.com/questions/15688607/nhibernate-one-to-one-relationship

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!