将两个类映射到同一张表

Posted

技术标签:

【中文标题】将两个类映射到同一张表【英文标题】:Map two classes to the same table 【发布时间】:2019-01-17 16:18:03 【问题描述】:

在旧版数据库中有一个 NODES 表,其中包含十几个“小”列和一个 LOB 列。 NodeEntity 类映射到 NODES 表。

出于性能目的,我不想在每次访问数据库时都加载 LOB 列。我知道实现这一目标的两种方法:

延迟加载的属性 分离实体类(思路取自here)

当您只从数据库加载数据时,延迟加载的属性很好。但是,如果您必须保存实体,那么如果您忘记事先获取延迟加载的属性,就会有丢失数据的风险。

所以我选择了第二种方法。

我创建了单独的小型 NodeEntityLite 类,其属性映射到 NODES 表的非 LOB 列。我修改了 NodeEntity 类,使其继承自 NodeEntityLite 类。我更改了我的类的映射并使用 union-subclass 进行继承。

public class NodeEntityLite 
  public virtual long Id  get; set; 
  public virtual string Code  get; set; 

public class NodeEntity : NodeEntityLite 
  public virtual string NOTE  get; set;  // type:clob

NodeEntityLite 类的 FluentNHibernate 映射是

public void Override(AutoMapping<NodeEntityLite> mapping) 
    mapping.Table("NODES");
    mapping.UseUnionSubclassForInheritanceMapping();

NodeEntity 类的 FluentNHibernate 映射是

public void Override(AutoMapping<NodeEntity> mapping) 
    mapping.Table("NODES");
    mapping.Map(e => e.NOTE).CustomType("StringClob").CustomSqlType("NCLOB");

我希望当我执行select n from NodeEntityLite n where n.Id = :p0 HQL 时,NHibernate 会生成没有 NOTE 列的 SQL 命令:

select nodeentity0_.ID as id1_87_, 
       nodeentity0_.CODE as code2_87_
    from from NODES nodeentity0_ 
    where nodeentity0_.ID=:p0;

但是 NHibernate 生成完全不同的 SQL 命令(NOTE 列没有按照我的预期跳过):

select nodeentity0_.ID as id1_87_, 
       nodeentity0_.CODE as code2_87_, 
       nodeentity0_.NOTE as note14_87_, 
       nodeentity0_.clazz_ as clazz_ 
    from ( select ID, CODE, NOTE, 1 as clazz_ from NODES ) nodeentity0_ 
    where nodeentity0_.ID=:p0;

我尝试更改继承并使用其他映射但没有成功。

问题是:我可以将多个类映射到 NHibernate 中的同一张表以访问不同的列吗?

如果是,请举个例子。


解决方案(基于 David Osborne 和 mxmissile 的建议)是不使用继承。我使用通用接口实现而不是类继承。工作代码如下:

public interface INodeLite 
  long Id  get; set; 
  string Code  get; set; 


public class NodeEntityLite : INodeLite 
  public virtual long Id  get; set; 
  public virtual string Code  get; set; 


public class NodeEntity : INodeLite 
  public virtual long Id  get; set; 
  public virtual string Code  get; set; 
  public virtual string NOTE  get; set;  // type:clob

...
public void Override(AutoMapping<NodeEntityLite> mapping) 
    mapping.Table("NODES");

...
public void Override(AutoMapping<NodeEntity> mapping) 
    mapping.Table("NODES");
    mapping.Map(e => e.NOTE).CustomType("StringClob").CustomSqlType("NCLOB");

【问题讨论】:

如果不使用继承并创建完全独立的实体会怎样? 继承很重要,因为处理 NodeEntityLite 实例的代码也必须接受 NodeEntity 的实例。 【参考方案1】:

无论继承如何,NH 都可以将不同类型映射到同一张表。我已经做到了,尽管没有继承。

您应该能够从 NodeEntityLite 覆盖中删除此行并实现它:

mapping.UseUnionSubclassForInheritanceMapping();

如果这被证明不成功,您可能需要进一步调整自动映射。不过这绝对是可能的。

【讨论】:

Fluent NHibernate 似乎检测到一个实体类继承自另一个类。 啊。你能告诉它不要在这个层次结构的覆盖中吗?或者也许使用组合而不是继承? Fluent NHibernate 检测到一个实体类继承自另一个类,如果我删除 UseUnionSubclassForInheritanceMapping,那么 Fluent NHibernate 会生成连接子类继承映射。您和@mxmissile 建议不要使用继承是个好主意。我更改了NodeEntityNodeEntityLite 类,以便它们实现一个没有继承的通用接口。

以上是关于将两个类映射到同一张表的主要内容,如果未能解决你的问题,请参考以下文章

如何 NHibernate 将多个类映射到同一个表

Hibernate 一个类映射到多个表

如何在phpmyadmin中关联同一张表的两个字段?

使用 JOIN'ed 映射表比同一张表中的多个字段更好?

如何将特定列单元格映射到同一张表中的其他特定列单元格?

Ruby on Rails Scaffolding:同一张表的两个外键