需要帮助NHibernate / Fluent NHibernate映射

时间:2010-03-17 01:49:24

标签: nhibernate fluent-nhibernate nhibernate-mapping mapping orm

假设您有以下表格结构:

                  ==============================  
                  | Case                       |
                  ==============================
                  | Id           | int         |
                  | ReferralType | varchar(10) |
        +---------| ReferralId   | int         |---------+
        |         ==============================         |
        |                      |                         |
        |                      |                         |
======================  ======================  ======================        
| SourceA            |  | SourceB            |  | SourceC            |
======================  ======================  ======================
| Id   | int         |  | Id   | int         |  | Id   | int         |
| Name | varchar(50) |  | Name | varchar(50) |  | Name | varchar(50) |
======================  ======================  ======================

基于ReferralType,ReferralId包含SourceA,SourceB或SourceC的id

我正在试图弄清楚如何使用Fluent NHibernate或简单的NHibernate将其映射到对象模型中。我尝试了很多不同的东西,但我没有成功。有什么想法吗?

对象模型可能类似于:

public class Case
{ 
  public int Id { get; set; }
  public Referral { get; set; }
}

public class Referral
{
  public string Type { get; set; }
  public int Id { get; set; }
  public string Name { get; set; }
}

2 个答案:

答案 0 :(得分:0)

<强>多对任何
如果表结构是固定的,并且您想要使用identity id生成器,我会将Source表映射为3个单独的类,并作为any引用映射到公共接口。

class Case
{
    public virtual IReferral Referral { get; set; }
}

class SourceA : IReferral
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual string Type { get { return "SourceA"; } }
}

interface IReferral
{
    int Id { get; set; }
    string Name { get; set; }
    string Type { get; }
}

public class CaseMap : ClassMap<Case>
{
    public CaseMap()
    {
        ReferencesAny(m => m.Referral)
            .EntityTypeColumn("ReferralType")
            .EntityIdentifierColumn("ReferralId")
            .AddMetaValue<SourceA>("SourceA")
            .AddMetaValue<SourceB>("SourceB")
            .AddMetaValue<SourceC>("SourceC")
            .IdentityType<int>();
    }
}

<强>联合子类
另一个选项是union-subclass,带有抽象基类映射。这允许急切提取,但您不能在子类表上使用identity生成器。

<class name="IReferral" abstract="true" table="Referral">
    <id name="Id">
        <generator class="hilo"/>
    </id>
    <property name="Name"/>
    <union-subclass name="SourceA" table="SourceA">
        <!-- class specific properties -->
    </union-subclass>
    <union-subclass name="SourceB" table="SourceB">
        <!-- class specific properties -->
    </union-subclass>
    <union-subclass name="SourceC" table="SourceC">
        <!-- class specific properties -->
    </union-subclass>
</class>

<强>子类
如果您可以更改表格,则可以使用subclass将所有3个推荐类映射到同一个表格。

<class name="IReferral" abstract="true" table="Referral" discriminator-value="null">
    <id name="Id">
        <generator class="identity"/>
    </id>
    <discriminator column="Discriminator" not-null="true" type="System.String"/>
    <property name="Name"/>
    <subclass name="SourceA" discriminator-value="SourceA">
        <!-- class specific properties -->
    </subclass>
    <subclass name="SourceB" discriminator-value="SourceB">
        <!-- class specific properties -->
    </subclass>
    <subclass name="SourceC" discriminator-value="SourceC">
        <!-- class specific properties -->
    </subclass>
</class>

答案 1 :(得分:0)

我设法通过以下方式让它发挥作用:

public class Case
{
  public virtual int? Id { get; set; }
  public virtual CaseReferral Referral { get; set; }
}
public class CaseReferral
{
  public virtual string Type { get; protected set; }
  public virtual int? ReferralId { get; protected set; }
  public virtual string Name { get { return null; }

  //NOTE: We need this for mapping reasons
  protected virtual int CaseId { get; set; }
  protected CaseReferral() { }
}

public class CaseSourceAReferral : CaseReferral
{
  private SourceA _sourceA;
  public virtual SourceA Source
  {
    get { return _sourceA; }
    protected set
    {
      _sourceA = value;

      Type = "SourceA";
      ReferralId = ( _sourceA != null ? _sourceA.Id : null );
    }
  }

  public override string Name { get { return Source.Name; } }

  //NOTE: Default constructor for mapping reasons
  protected CaseSourceAReferral() { }
  public CaseSourceAReferral( int caseId, SourceA source )
  {
    CaseId = caseId;
    Source = source;
  }
}

public class CaseMap : ClassMap<Case>
{
  public CaseMap()
  {
    Id( c => c.Id );
    References( c => c.Referral ).Column( "Id" );
  }
}

public class CaseReferralMap : ClassMap<CaseReferral>
{
  public CaseReferralMap()
  {
    Id( Reveal.Property<CaseReferral>( "CaseId") ).Column( "Id" );
    Map( r => r.Type ).Column( "ReferralType" );
    Map( r => r.ReferralId ).Column( "ReferralId" );
    DiscriminateSubClassesOnColumn( "ReferralType" );
  }
}

public class CaseSourceAReferralMap : SubclassMap<CaseSourceAReferral>
{
  public CaseSourceAReferralMap()
  {
    DiscriminatorValue( "SourceA" );
    References( r => r.Source ).Column( "ReferralId" );
  }
}