【问题标题】:How to map an interface in nhibernate?如何在 nhibernate 中映射接口?
【发布时间】:2010-02-18 06:17:50
【问题描述】:

我正在使用两个类 NiceCustomerRoughCustomer 实现接口 ICustomer

ICustomer 有四个属性。它们是:

  1. Property Id() As Integer
  2. Property Name() As String
  3. Property IsNiceCustomer() As Boolean
  4. ReadOnly Property AddressFullText() As String

我不知道如何将接口ICustomer映射到数据库。

我在内部异常中收到这样的错误。

关联指的是未映射的类:ICustomer

我正在使用 Fluent 和 NHibernate。

【问题讨论】:

  • 我认为您不需要像这样映射任何接口..您能发布您的映射文件吗?谢谢
  • 感谢您回复马赫什。但正如凯文所说,我们不能在 nhibernate 中映射接口。我已将接口更改为基类。

标签: fluent-nhibernate


【解决方案1】:

可以直接映射到 NHibernate 中的接口,方法是在配置阶段插入 EmptyInterceptor。这个拦截器的工作是为您在映射文件中定义的接口提供实现。

public class ProxyInterceptor : EmptyInterceptor
{
    public ProxyInterceptor(ITypeHandler typeHandler) {
        // TypeHandler is a custom class that defines all Interface/Poco relationships
        // Should be written to match your system
    }

    // Swaps Interfaces for Implementations
    public override object Instantiate(string clazz, EntityMode entityMode, object id)
    {
        var handler = TypeHandler.GetByInterface(clazz);
        if (handler == null || !handler.Interface.IsInterface) return base.Instantiate(clazz, entityMode, id);
        var poco = handler.Poco;
        if (poco == null) return base.Instantiate(clazz, entityMode, id);

        // Return Poco for Interface
        var instance = FormatterServices.GetUninitializedObject(poco);
        SessionFactory.GetClassMetadata(clazz).SetIdentifier(instance, id, entityMode);

        return instance;
    }

}

在此之后,所有的关系和映射都可以定义为接口。

public Parent : IParent {
    public int ID { get; set; }
    public string Name { get; set; }
    public IChild Child { get; set; }
}

public Child : IChild {
    public int ID { get; set; }
    public string Name { get; set; }
}

public class ParentMap : ClassMap<IParent>
{
    public ParentMap()
    {
        Id(x => x.ID).GeneratedBy.Identity().UnsavedValue(0);
        Map(x => x.Name)
    }
}   

...

如果您想实现 ORM 的真正解耦,将所有配置/映射放在一个单独的项目中并且只引用接口,这种技术非常有用。然后,您的域层不会被 ORM 污染,如果需要,您可以在稍后阶段替换它。

【讨论】:

  • 你能在配置中添加一个使用 ProxyInterceptor 的例子吗?我现在才开始使用 Fluent Nhibernate,对配置部分还不够熟悉,不知道在哪里指定代理...
  • 我能够让它工作,但问题是域层仍然被 ORM 特定的方法过度污染——主要是属性的设置器。 ORM 需要能够在每个字段上设置一个值,而在 Domain 对象中,我不想更改对象的 Id 字段(与许多其他只读属性相同)。
【解决方案2】:

你是怎么查询的?如果您使用 HQL,则需要使用 HBM 文件导入接口的命名空间,其中包含以下行:

<import class="name.space.ICustomer, Customers" />

如果您使用 Criteria,您应该能够查询 ICustomer,它会返回两种客户类型。

如果您通过 HasMany、HasManyToMany 或 References 映射具有客户的类,则需要使用通用形式:

References<NiceCustomer>(f=>f.Customer)

如果你想让它处理任何一个,你需要让它们成为子类

Subclassmap<NiceCustomer>

在这种情况下,我认为您将需要基类 Customer 并将其用于外部类中的泛型类型参数:

References<Customer>(f=>f.Customer)

无论如何,你不应该改变你的领域模型来解决这个问题,它仍然应该在外部类上有一个 ICustomer。

我不确定 1.0RTM 是否具有适用于引用的通用表单,但快速浏览更改应该会显示更改,我认为这是两行添加。

【讨论】:

    【解决方案3】:

    无法在 nhibernate 中映射接口。如果您的目标是能够使用通用类型进行查询以检索这两种类型的客户,则可以使用多态查询。只需让您的两个类都实现接口并正常映射类。请参阅此参考:

    https://www.hibernate.org/hib_docs/nhibernate/html/queryhql.html(第 11.6 节)

    【讨论】:

    • 我也尝试过多态查询,但它不起作用。那个未映射的接口客户仍然有问题。所以现在让它成为一个可以正常工作的基类。非常感谢凯文。
    • “命名的持久类是一个接口是完全可以接受的。然后您可以使用 元素声明该接口的实现类。”来自knol.google.com/k/fabio-maulo/…
    • 此答案中的链接已损坏。请更新链接或为您的答案添加更多详细信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多