1

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

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 不扩展 Content 而是像这样的重复类,问题就会消失:

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() {...}
}

所以现在一切都很好,但我不喜欢有这么多代码重复的事实,在我看来,必须有某种映射配置来强制 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);
}

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

4

1 回答 1

1

要仅定义一次类映射和属性,您必须定义一个基类并定义映射,通过该映射,UseUnionSubclassForInheritanceMapping您可以使用从该基类派生的每个实体的独立表。

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

为此,请创建一个基类和 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();
    }
}
于 2013-10-19T07:21:13.207 回答