我有一个包含一些属性和一些方法的类
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);
}
任何想法如何摆脱代码重复?
答案 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();
}
}