流利的NHibernate HasOne选择N + 1问题

时间:2018-06-09 11:48:22

标签: orm fluent-nhibernate

我有以下数据模型:人可以有一个CurrentSpouse,这个当前的配偶可以有一辆车。数据模型仅用于演示。

public class BDOPerson
{
    public virtual long? OID { get; set; }
    public virtual string FirstName { get; set; }
    public virtual string SureName { get; set; }
    public virtual BDOCurrentSpouse CurrentSpouse { get; set; }
}

public class PersonMap : ClassMap<BDOPerson>
{
    public PersonMap()
    {
        Table("T0001_Person");
        Id(x => x.OID).Column("T0001OID").GeneratedBy.Increment();
        Map(x => x.FirstName).Not.Nullable().Column("T0001Firstname");
        Map(x => x.SureName).Not.Nullable().Column("T0001Surename");

        References(x => x.CurrentSpouse).Nullable().Column("T0002_CurrentSpouseOID").Unique(); //HasOne opossite
    }
}

CurrentSpouse

public class BDOCurrentSpouse
{
    public virtual long? OID { get; set; }
    public virtual string FirstName { get; set; }
    public virtual string SureName { get; set; }

    public virtual BDOPerson Person { get; set; }
    public virtual BDOCar Car { get; set; }
}

public class CurrentSpouseMap : ClassMap<BDOCurrentSpouse>
{
    public CurrentSpouseMap()
    {
        Table("T0002_CurrentSpouse");
        Id(x => x.OID).Column("T0002OID").GeneratedBy.Increment();
        Map(x => x.FirstName).Not.Nullable().Column("T0002Firstname");
        Map(x => x.SureName).Not.Nullable().Column("T0002Surename");

        HasOne(x => x.Person).PropertyRef(x => x.CurrentSpouse);
        References(x => x.Car).Nullable().Column("T0003_CarOID");
    }
}

汽车

public class BDOCar
{
    public virtual long? OID { get; set; }
    public virtual string PlateId { get; set; }
}

public class CarMap : ClassMap<BDOCar>
{
    public CarMap()
    {
        Table("T0003_Car");
        Id(x => x.OID).Column("T0003OID").GeneratedBy.Increment();
        Map(x => x.PlateId).Not.Nullable().Column("T0003PlateId");
    }
}

数据填充:

using (var session = _sessionFactory.OpenSession())
{
    var isolationLevel = IsolationLevel.ReadCommitted;
    using (var transaction = session.BeginTransaction(isolationLevel))
    {
        var currentSpouse = new BDOCurrentSpouse { FirstName = "Ema", SureName = "NiceLooking" };
        var person = new BDOPerson { FirstName = "John", SureName = "Doe", CurrentSpouse = currentSpouse};

        var car = new BDOCar { PlateId = "1234567" };
        session.Save(car);
        car = new BDOCar { PlateId = "336699" };
        session.Save(car);

        currentSpouse.Car = car;
        session.Save(currentSpouse);
        session.Save(person);

        transaction.Commit();
    }
}

选择数据 - 问题1

using (var session = _sessionFactory.OpenSession())
{
    var isolationLevel = IsolationLevel.ReadCommitted;
    using (var transaction = session.BeginTransaction(isolationLevel))
    {
        var v = session.Query<BDOPerson>().Fetch(x => x.CurrentSpouse).ToList();                    
        transaction.Commit();
    }
}

选择

的结果查询
select bdoperson0_.T0001OID as t1_2_0_, bdocurrent1_.T0002OID as t1_1_1_, bdoperson0_.T0001Firstname as t2_2_0_, bdoperson0_.T0001Surename as t3_2_0_, bdoperson0_.T0002_CurrentSpouseOID as t4_2_0_, bdocurrent1_.T0002Firstname as t2_1_1_, bdocurrent1_.T0002Surename as t3_1_1_, bdocurrent1_.T0003_CarOID as t4_1_1_ from T0001_Person bdoperson0_ left outer join T0002_CurrentSpouse bdocurrent1_ on bdoperson0_.T0002_CurrentSpouseOID=bdocurrent1_.T0002OID

SELECT bdoperson0_.T0001OID as t1_2_0_, bdoperson0_.T0001Firstname as t2_2_0_, bdoperson0_.T0001Surename as t3_2_0_, bdoperson0_.T0002_CurrentSpouseOID as t4_2_0_ FROM T0001_Person bdoperson0_ WHERE bdoperson0_.T0002_CurrentSpouseOID=?

获得第二次选择的原因是什么?第二个选择创建N + 1问题 - 作为第一个选择的结果,对于DB中的每一行,完成特殊的第二个选择。

出于测试目的,我试图获取人

using (var session = _sessionFactory.OpenSession())
{
    var isolationLevel = IsolationLevel.ReadCommitted;
    using (var transaction = session.BeginTransaction(isolationLevel))
    {
        var v = session.Query<BDOPerson>().Fetch(x => x.CurrentSpouse).ThenFetch(x => x.Person).ToList();
        transaction.Commit();
    }
}

但这并未解决问题:

select bdoperson0_.T0001OID as t1_2_0_, bdocurrent1_.T0002OID as t1_1_1_, bdoperson2_.T0001OID as t1_2_2_, bdoperson0_.T0001Firstname as t2_2_0_, bdoperson0_.T0001Surename as t3_2_0_, bdoperson0_.T0002_CurrentSpouseOID as t4_2_0_, bdocurrent1_.T0002Firstname as t2_1_1_, bdocurrent1_.T0002Surename as t3_1_1_, bdocurrent1_.T0003_CarOID as t4_1_1_, bdoperson2_.T0001Firstname as t2_2_2_, bdoperson2_.T0001Surename as t3_2_2_, bdoperson2_.T0002_CurrentSpouseOID as t4_2_2_ from T0001_Person bdoperson0_ left outer join T0002_CurrentSpouse bdocurrent1_ on bdoperson0_.T0002_CurrentSpouseOID=bdocurrent1_.T0002OID left outer join T0001_Person bdoperson2_ on bdocurrent1_.T0002OID=bdoperson2_.T0002_CurrentSpouseOID

SELECT bdoperson0_.T0001OID as t1_2_0_, bdoperson0_.T0001Firstname as t2_2_0_, bdoperson0_.T0001Surename as t3_2_0_, bdoperson0_.T0002_CurrentSpouseOID as t4_2_0_ FROM T0001_Person bdoperson0_ WHERE bdoperson0_.T0002_CurrentSpouseOID=?

如何防止在映射中设置为HasOne的对象的额外选择?

0 个答案:

没有答案