Nhibernate被类继承混淆并返回混合结果

时间:2013-10-18 10:40:11

标签: c#-4.0 nhibernate inheritance fluent-nhibernate fluent-nhibernate-mapping

我有一个包含一些属性和一些方法的类

public class Content
{
    public int Id { get; set; }
    public string Application { get; set; }
    public string Property1 { get; set; }
    public string Property2 { get; set; }

    public override bool Equals(object obj) {...}
    public override int GetHashCode() {...}
}

使用这个Fluent NHibernate映射:

public class ContentMapping : ClassMap<Content>
{ 
   public ContentMapping()
   {
      Table("vw_all_contents");

      CompositeId()
                .KeyProperty(x => x.Id, "id")
                .KeyProperty(x => x.Application, "application");

      Map(x => x.Property1, "property1");
      Map(x => x.Property2, "property2");
   }
}

到目前为止一切正常。

我现在想要填充相同的对象,但是使用表连接到另一个数据库的联合表。

所以我有:

public class ContentOnProductionDatabase : Content { }

使用映射:

public class ContenOnProductionDatabasetMapping : ClassMap<ContentOnProductionDatabase>
{ 
   public ContentOnProductionDatabaseMapping()
   {
      Table("vw_federated_all_contents");

      CompositeId()
                .KeyProperty(x => x.Id, "id")
                .KeyProperty(x => x.Application, "application");

      Map(x => x.Property1, "property1");
      Map(x => x.Property2, "property2");
   }
}

这就是NHibernate真正混淆的地方,并且查询返回两个数据库的混合结果。

如果我的ContentOnProductionDatabase不扩展内容,而是像这样的重复类,则问题就消失了:

public class ContentOnProductionDatabaseMapping
{
    public int Id { get; set; }
    public string Application { get; set; }
    public string Property1 { get; set; }
    public string Property2 { get; set; }

    public override bool Equals(object obj) {...}
    public override int GetHashCode() {...}
}

所以现在一切都很好,但我不喜欢这么多代码重复这一事实,在我看来必须有某种Mapping配置来迫使NHibernate忽略继承并区分这两者,特别是因为它们映射到不同的数据库。

存储库框架是一个内置的框架,用于处理会话和查询。

public class ContentRepository : NHibernateRepositoryBase, IContentRepository
{
    public ContentRepository(INHibernateContext context, ISettingsManager settingsManager): base(context){   }

    public Content ReadContent(int id, string application)
    {
        using (ISessionContainer container = Context.GetSessionContainer())
        {
            return
                container.AsQueryable<Content>()
                    .FirstOrDefault(c => c.Id == id && c.Application == application);
                    // All queries using <Content> return the correct results
        }
    }

    public ContentOnProductionDataBase ReadFederatedContent(int id, string application)
    {
        using (ISessionContainer container = Context.GetSessionContainer())
        {
            return
                container.AsQueryable<ContentOnProductionDataBase>()
                    .FirstOrDefault(c => c.Id == id && c.Application == application);
                    // All queries using <ContentOnProductionDataBase> return the combined results of <Content> and <ContentOnProductionDataBase>
        }
    }
}

在container.AsQueryable内部通过调用它来工作:

public IQueryable<TEntity> AsQueryable<TEntity>() where TEntity : class
{
  return LinqExtensionMethods.Query<TEntity>(this.Session);
}

任何想法如何摆脱代码重复?

1 个答案:

答案 0 :(得分:1)

要仅定义类映射和属性一次,您必须定义一个基类并使用UseUnionSubclassForInheritanceMapping定义映射,这将允许您使用从该基类派生的每个实体的独立表。 / p>

您不必,但您应该将您的基类声明为抽象,因为它没有数据库表示。所以坚持基类会失败!意思是,您不希望任何人将其用作实体,而是使用派生类...

为此,创建一个基类和2个派生类,每个类应存储在一个表中。

public abstract class ContentBase
{
    public virtual int Id { get; set; }
    public virtual string Application { get; set; }
    public virtual string Property1 { get; set; }
    public virtual string Property2 { get; set; }
    public override bool Equals(object obj)
    {
        [..]
    }
    public override int GetHashCode()
    {
        [..]
    }
}

public class Content : ContentBase
{
}

public class ContentOnProductionDatabaset : ContentBase
{
}

基类的映射必须调用UseUnionSubclassForInheritanceMapping,否则nHibernate会合并类。

public class ContentBaseMapping : ClassMap<ContentBase>
{
    public ContentBaseMapping()
    {
        UseUnionSubclassForInheritanceMapping();

        CompositeId()
                  .KeyProperty(x => x.Id, "id")
                  .KeyProperty(x => x.Application, "application");

        Map(x => x.Property1, "property1");
        Map(x => x.Property2, "property2");
    }
}

子类映射只需要定义基类是抽象的。 在这里,您还可以定义实体应使用的每个表名。

public class ContentMapping : SubclassMap<Content>
{
    public ContentMapping()
    {
        Table("vw_all_contents");

        Abstract();
    }
}

public class ContentOnProductionDatabaseMapping : SubclassMap<ContentOnProductionDatabaset>
{
    public ContentOnProductionDatabaseMapping()
    {
        Table("vw_federated_all_contents");

        Abstract();
    }
}