Table-每个子类的流畅 nhibernate 不工作

Table-per-subclass fluent nhibernate not working

我定义了以下 classes:

我的数据库中有这些 table:

我流畅的 NHibernate 映射是:

public class BusinessUnitMap : ClassMap<BusinessUnit>
{
    public BusinessUnitMap()
    {
        Table("BusinessUnits");

        Id(x => x.Id);

        Map(x => x.Code);
        Map(x => x.Name);
        Map(x => x.ParentId);
        Map(x => x.Type).Column("Type").CustomType<BusinessUnitType>();
    }
}

public class CompanyMap : SubclassMap<Company>
{
    public CompanyMap()
    {
        Table("CompanyData");

        KeyColumn("BusinessUnitID");

        Map(x => x.Something);
    }
}

public class FranchiseeMap : SubclassMap<Franchisee>
{
    public FranchiseeMap()
    {
        Table("FranchiseeData");

        KeyColumn("BusinessUnitID");

        Map(x => x.SomethingDifferent);
    }
}

public class StoreMap : SubclassMap<Store>
{
    public StoreMap()
    {
        Table("StoreData");

        KeyColumn("BusinessUnitID");

        Map(x => x.SomethingElse);
    }
}

问题 #1 据我所知,我的代码和数据库设置与我能够找到的每个示例相同。根据这些文章,NHibernate 应该足够聪明,可以在我查询特定的 subclass 时确定要实例化的 subclass。但是,当我执行以下语句时:

var result = Session.QueryOver<BusinessUnit>()
                    .Where(x => x.Code == "Acme")
                    .SingleOrDefault();

抛出异常,因为它无法创建抽象 BusinessUnit class 的实例。我能让它工作的唯一方法是将 Company 指定为 QueryOver 的类型参数。

我已经确认使用鉴别器会中断,因为 NHibernate 正在寻找存在于单个 table 中的所有列。但是,如果没有它,我很难看到 NHibernate 如何知道要实例化什么类型。

我做错了什么?问题出在我的映射中,我查询的方式...?

问题 #2 当我将查询更改为如下内容时:

public T WithCode<T>(String code)
    where T : BusinessUnit
{
    var result = Session.QueryOver<T>()
                        .Where(x => x.Code == code)
                        .SingleOrDefault();

    return result;
}

我收到一个异常,表明 UPDATE 语句与外键约束冲突。更新声明!!!!显然有些事情仍然不对。 QueryOver 调用如何导致 UPDATE 语句?我错过了什么?

您的数据似乎不一致。将鉴别器映射与可选的一起使用可能会更好。如果您真的不需要代码中的 BusinessUnitType 属性,那么只需删除 属性 Type

周围的所有内容
public enum BusinessUnitType
{
    Company,
    Franchisee
}

public abstract class BusinessUnit
{
    public virtual int Id { get; set; }
    public virtual string Code { get; set; }
    public virtual string Name { get; set; }
    public virtual BusinessUnit Parent { get; set; }
    public abstract BusinessUnitType Type { get; }
}

public class Company : BusinessUnit
{
    public virtual string Something { get; set; }

    public override BusinessUnitType Type { get { return BusinessUnitType.Company; } }
}

public class Franchisee : BusinessUnit
{
    public virtual string SomethingDifferent { get; set; }

    public override BusinessUnitType Type { get { return BusinessUnitType.Franchisee; } }
}

public class BusinessUnitMap : ClassMap<BusinessUnit>
{
    public BusinessUnitMap()
    {
        Table("BusinessUnits");

        Id(x => x.Id);

        Map(x => x.Code);
        Map(x => x.Name);
        References(x => x.Parent);

        DiscriminateSubClassesOnColumn("Type");

        Map(x => x.Type, "Type")
            .Access.None()
            .CustomType<BusinessUnitType>().ReadOnly();
    }
}

public class CompanyMap : SubclassMap<StrangeTablePerSubclass.Company>
{
    public CompanyMap()
    {
        DiscriminatorValue((int)new Company().Type);

        Join("CompanyData", join =>
        {
            join.KeyColumn("BusinessUnitID");
            join.Optional();
            join.Map(x => x.Something);
        });
    }
}

public class FranchiseeMap : SubclassMap<Franchisee>
{
    public FranchiseeMap()
    {
        DiscriminatorValue((int)new Franchisee().Type);
        Join("FranchiseeData", join =>
        {
            join.KeyColumn("BusinessUnitID");
            join.Optional();
            join.Map(x => x.SomethingDifferent);
        });
    }
}