如何在没有数据库持久性的情况下让NHibernate知道一流的“Null对象”?

时间:2021-04-10 21:10:38

I would like to make use of the Null Object pattern in my domain, but I don't want to have records in my database that relate to it - I would prefer it if NHibernate were able to map a SQL null value to my Null object, and vice versa.

我想在我的域中使用Null对象模式,但我不希望在我的数据库中有与之相关的记录 - 如果NHibernate能够将SQL null值映射到我的Null对象,我宁愿这样做,反之亦然。

Is this possible (using Fluent NHibernate for mappings)

这是可能的(使用Fluent NHibernate进行映射)

P.S. This seems like it is a fairly common issue people are looking to resolve, but I wonder why I have struggled to find an answer.

附:这似乎是人们希望解决的一个相当普遍的问题,但我想知道为什么我一直在努力寻找答案。

Edit: Judging by this blog entry it doesn't look like it's going to be directly possible: NHibernate & Null Object Pattern: The Options

编辑:通过这篇博客文章判断它看起来不会直接成为可能:NHibernate&Null对象模式:选项

3 个解决方案

#1


In not fluent nhibernate you can use an Import mapping that will not persist to the database like this;

在不流畅的nhibernate中,您可以使用不会像这样持久存储到数据库的导入映射;

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
      namespace="MyProject.MiddleTier"    
      assembly="MyProject.MiddleTier">
   <import class="ThingNotToPersist"/>
</hibernate-mapping>

Don't know how this work in fluent but hopefully it gives you a starter.

不知道这种工作如何流利,但希望它能给你一个启动。

#2


The answer is... you can't. Oren says "NHibernate's concept of null isn't something that you can easily change, and it doesn't go through an interceptor to do so. You could use null objects for value types (using UserType), but not for entities."

答案是......你做不到。 Oren说“NHibernate的null概念不是你可以轻易改变的东西,而且它不会通过拦截器来实现。你可以使用null对象作为值类型(使用UserType),但不能用于实体。”

#3


Okay, since this question was posted, NHibernate 3 was released - maybe something is possible now?

好的,自从这个问题发布以来,NHibernate 3已经发布了 - 也许现在有可能吗?

I'm not willing to let this go - I want to use the null-object pattern, and I'm not going to be satisfied with "you can't", so let's think about ways to achieve this!

我不愿意放弃这一点 - 我想使用空对象模式,我不会满足于“你不能”,所以让我们想办法实现这个目标!

One idea I've come across in several posts and notes around the web, is to use two properties - one with public (unmapped) and one with private (mapped) access - so the get-accessor for the public property would be something like return MyPrivate ?? MyType.NullObject ... I've eliminated that idea, because it creates problems with the query interface - you can't query on the public property, because it's not mapped. So we can forget that approach.

我在网上的几个帖子和笔记中遇到的一个想法是使用两个属性 - 一个具有公共(未映射)和一个具有私有(映射)访问 - 因此公共属性的get-accessor将类似于返回MyPrivate ?? MyType.NullObject ...我已经消除了这个想法,因为它会产生查询接口的问题 - 你无法查询公共属性,因为它没有被映射。所以我们可以忘记这种方法。

I have two ideas I have not seen explored anywhere:

我有两个在任何地方都没有看过的想法:

Use an interceptor to change the property value before/after read/write.

使用拦截器在读/写之前/之后更改属性值。

Someone mentioned an interceptor won't work, but bear with me... in pseudo-code:

有人提到拦截器不起作用,但请耐心等待...伪代码:

class Foo
{
    public Bar Bar { get; set; }
}

class Bar
{
    public static Bar None;
}

class MyInterceptor
{
    public void AfterLoad(IEntity object)
    {
        foreach (property in object)
            if (property.type == typeof(Bar) && property.value == null)
                object[property].value = Bar.None;
    }

    public void BeforeSave(IEntity object)
    {
        foreach (property in object)
            if (property.type == typeof(Bar) && property.value == Bar.None)
                object[property].value = null;
    }

    public void AfterSave(IEntity object)
    {
        foreach (property in object)
            if (property.type == typeof(Bar) && property.value == null)
                object[property].value = Bar.None;
    }
}

In short, substitute nulls with the null-object on load; before saving, substitute null-object with an actual null-value, and after saving, substitute back the null-object.

简而言之,在加载时使用null-object替换null;在保存之前,用实际的空值替换null-object,并在保存之后,替换null对象。

When using the query API, of course you would need to query for actual null-values, but if you have some sort of criteria-builder or factory-class over the query API, you can account for that there.

当使用查询API时,您当然需要查询实际的空值,但如果您在查询API上有某种条件构建器或工厂类,则可以在那里考虑。

Extend your type to a dedicated null-object type and make it non-persistent. Somehow.

将您的类型扩展为专用的null对象类型,并使其成为非持久性类型。不知何故。

Just a thought - suppose you were to extend your type into a dedicated null-object-type. Something along the lines of:

只是一个想法 - 假设您要将类型扩展为专用的null-object-type。有点像:

class Bar
{
    public static NullBar; // instace of NullBar
}

class NullBar : Bar
{
    // ...
}

Now that NullBar is a dedicated type extending Bar, can we somehow tell NHibernate NOT to map the Nullar type, even though it extends Bar, which is mapped?

既然NullBar是一个专用类型扩展Bar,我们能不能告诉NHibernate不要映射Nullar类型,即使它扩展了Bar,它被映射了?

Those are my ideas - either of those sound plausible?

那些是我的想法 - 这些听起来有道理吗?

(I'm an NHibernate noob, btw - but I'm persistent, and not in the sense that you can save me and set me aside for later.)

(我是一个NHibernate noob,顺便说一句 - 但我坚持不懈,而不是因为你能救我并把我放在一边等待。)

#1


In not fluent nhibernate you can use an Import mapping that will not persist to the database like this;

在不流畅的nhibernate中,您可以使用不会像这样持久存储到数据库的导入映射;

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
      namespace="MyProject.MiddleTier"    
      assembly="MyProject.MiddleTier">
   <import class="ThingNotToPersist"/>
</hibernate-mapping>

Don't know how this work in fluent but hopefully it gives you a starter.

不知道这种工作如何流利,但希望它能给你一个启动。

#2


The answer is... you can't. Oren says "NHibernate's concept of null isn't something that you can easily change, and it doesn't go through an interceptor to do so. You could use null objects for value types (using UserType), but not for entities."

答案是......你做不到。 Oren说“NHibernate的null概念不是你可以轻易改变的东西,而且它不会通过拦截器来实现。你可以使用null对象作为值类型(使用UserType),但不能用于实体。”

#3


Okay, since this question was posted, NHibernate 3 was released - maybe something is possible now?

好的,自从这个问题发布以来,NHibernate 3已经发布了 - 也许现在有可能吗?

I'm not willing to let this go - I want to use the null-object pattern, and I'm not going to be satisfied with "you can't", so let's think about ways to achieve this!

我不愿意放弃这一点 - 我想使用空对象模式,我不会满足于“你不能”,所以让我们想办法实现这个目标!

One idea I've come across in several posts and notes around the web, is to use two properties - one with public (unmapped) and one with private (mapped) access - so the get-accessor for the public property would be something like return MyPrivate ?? MyType.NullObject ... I've eliminated that idea, because it creates problems with the query interface - you can't query on the public property, because it's not mapped. So we can forget that approach.

我在网上的几个帖子和笔记中遇到的一个想法是使用两个属性 - 一个具有公共(未映射)和一个具有私有(映射)访问 - 因此公共属性的get-accessor将类似于返回MyPrivate ?? MyType.NullObject ...我已经消除了这个想法,因为它会产生查询接口的问题 - 你无法查询公共属性,因为它没有被映射。所以我们可以忘记这种方法。

I have two ideas I have not seen explored anywhere:

我有两个在任何地方都没有看过的想法:

Use an interceptor to change the property value before/after read/write.

使用拦截器在读/写之前/之后更改属性值。

Someone mentioned an interceptor won't work, but bear with me... in pseudo-code:

有人提到拦截器不起作用,但请耐心等待...伪代码:

class Foo
{
    public Bar Bar { get; set; }
}

class Bar
{
    public static Bar None;
}

class MyInterceptor
{
    public void AfterLoad(IEntity object)
    {
        foreach (property in object)
            if (property.type == typeof(Bar) && property.value == null)
                object[property].value = Bar.None;
    }

    public void BeforeSave(IEntity object)
    {
        foreach (property in object)
            if (property.type == typeof(Bar) && property.value == Bar.None)
                object[property].value = null;
    }

    public void AfterSave(IEntity object)
    {
        foreach (property in object)
            if (property.type == typeof(Bar) && property.value == null)
                object[property].value = Bar.None;
    }
}

In short, substitute nulls with the null-object on load; before saving, substitute null-object with an actual null-value, and after saving, substitute back the null-object.

简而言之,在加载时使用null-object替换null;在保存之前,用实际的空值替换null-object,并在保存之后,替换null对象。

When using the query API, of course you would need to query for actual null-values, but if you have some sort of criteria-builder or factory-class over the query API, you can account for that there.

当使用查询API时,您当然需要查询实际的空值,但如果您在查询API上有某种条件构建器或工厂类,则可以在那里考虑。

Extend your type to a dedicated null-object type and make it non-persistent. Somehow.

将您的类型扩展为专用的null对象类型,并使其成为非持久性类型。不知何故。

Just a thought - suppose you were to extend your type into a dedicated null-object-type. Something along the lines of:

只是一个想法 - 假设您要将类型扩展为专用的null-object-type。有点像:

class Bar
{
    public static NullBar; // instace of NullBar
}

class NullBar : Bar
{
    // ...
}

Now that NullBar is a dedicated type extending Bar, can we somehow tell NHibernate NOT to map the Nullar type, even though it extends Bar, which is mapped?

既然NullBar是一个专用类型扩展Bar,我们能不能告诉NHibernate不要映射Nullar类型,即使它扩展了Bar,它被映射了?

Those are my ideas - either of those sound plausible?

那些是我的想法 - 这些听起来有道理吗?

(I'm an NHibernate noob, btw - but I'm persistent, and not in the sense that you can save me and set me aside for later.)

(我是一个NHibernate noob,顺便说一句 - 但我坚持不懈,而不是因为你能救我并把我放在一边等待。)