在 NHibernate 对象上使用动态代理

发布于 2024-08-08 09:04:07 字数 2190 浏览 7 评论 0原文

我正在尝试使用 Castle.DynamicProxy2 来清理 NHibernate 持久类中的代码。这是它的一个简单版本。

Pet 类:

public class Pet
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

及其映射文件:

<class name="Pet" table="Pet">
  <id name="Id" column="Id" unsaved-value="0">
    <generator class="native"/>
  </id>
  <property name="Name" column="Name"/>
  <property name="Age" column="Age"/>
</class>

需要审核 Pet 类的实例。通常,名称和年龄属性不会是自动属性,并且会包含记录值更改的逻辑。现在,我正在考虑使用代理在属性设置器中注入审核逻辑。为此,我创建了 Auditor IInterceptor:

public class Auditor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        // Do something to record changes
        invocation.Proceed();
    }
}

使用 Castle.DynamicProxy2 创建 Pet 类的审核实例非常简单。

Pet aPet = proxyGenerator.CreateClassProxy<Pet>(new Auditor());
aPet.Name = "Muffles"; // The Auditor instance would record this.
aPet.Age = 4;          // and this too...

现在问题来了。由于 Pet 是持久化的,系统需要处理通过 NHibernate 获取的 Pet 实例。我想要发生的是 NHibernate 自动返回 Pet 代理的实例,如下所示:

// I would imagine an instance of Auditor being created implicitly
ICriteria criteria = session.CreateCriteria(typeof(Pet));
criteria.Add(Expression.Expression.Eq("Name", "Muffles"));

// return a list of Pet proxies instead
// so changes can be recorded.
IList<Pet> result = criteria.List<Pet>();

Pet aPet = result[0];
aPet.Age = aPet.Age + 1;

// I expect this to succeed since the proxy is still a Pet instance
session.Save(aPet); 

我想到了类似的方法来解决它:

ICriteria criteria = session.CreateCriteria(ProxyHelper.GetProxyType<Pet>());
criteria.Add(Expression.Expression.Eq("Name", "Muffles"));

// use List() instead of List<T>()
// and IList instead of IList<Pet>
IList results = criteria.List();

其中 ProxyHelper.GetProxyType() 将返回缓存的 Pet 代理类型。主要缺点是该解决方案不适用于通用列表(例如IList)。我试图清理的现有系统广泛使用了它们。

因此,我希望是否有人有任何解决方法或对我所做的事情是否可取有任何见解。

谢谢一百万,

卡洛斯

I'm trying to use Castle.DynamicProxy2 to cleanup code within NHibernate persisted classes. Here is a simple version of it.

The Pet class:

public class Pet
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

And its mapping file:

<class name="Pet" table="Pet">
  <id name="Id" column="Id" unsaved-value="0">
    <generator class="native"/>
  </id>
  <property name="Name" column="Name"/>
  <property name="Age" column="Age"/>
</class>

There is a need to audit instances of the Pet class. Normally, the properties Name and Age would not be auto-properties and would contain logic to record value changes. Now, I'm thinking of using proxies to inject auditing logic within property setters. To do that, I created the Auditor IInterceptor:

public class Auditor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        // Do something to record changes
        invocation.Proceed();
    }
}

It's simple enough to create an audited instance of the Pet class using Castle.DynamicProxy2.

Pet aPet = proxyGenerator.CreateClassProxy<Pet>(new Auditor());
aPet.Name = "Muffles"; // The Auditor instance would record this.
aPet.Age = 4;          // and this too...

Now here comes the problem. Since Pet is persisted, the system would need to work on instances of Pet fetched via NHibernate. What I want to happen is that NHibernate to return instances of Pet proxy automatically like so:

// I would imagine an instance of Auditor being created implicitly
ICriteria criteria = session.CreateCriteria(typeof(Pet));
criteria.Add(Expression.Expression.Eq("Name", "Muffles"));

// return a list of Pet proxies instead
// so changes can be recorded.
IList<Pet> result = criteria.List<Pet>();

Pet aPet = result[0];
aPet.Age = aPet.Age + 1;

// I expect this to succeed since the proxy is still a Pet instance
session.Save(aPet); 

I've though of something like this to get around it:

ICriteria criteria = session.CreateCriteria(ProxyHelper.GetProxyType<Pet>());
criteria.Add(Expression.Expression.Eq("Name", "Muffles"));

// use List() instead of List<T>()
// and IList instead of IList<Pet>
IList results = criteria.List();

where ProxyHelper.GetProxyType<Pet>() would return the cached Pet proxy type. The main disadvantage is that this solution would not work on generic lists (e.g. IList<Pet>). The existing system I'm trying to clean up makes use of them extensively.

So I'm hoping if anyone has any workaround or any insight on whether or not what I'm doing is advisable.

Thanks a million,

Carlos

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

舂唻埖巳落 2024-08-15 09:04:07

您可以使用 NHibernate 事件监听器

它们挂钩 NHibernate 的事件系统并拦截此类操作。由于明显的运行时创建代理性能提升,这甚至可能比使用代理更好。

该链接实际上显示了一个审核应用程序示例。

You could use NHibernate Event Listeners.

These hook into NHibernate's event system and intercept such actions. This may even be a better idea than using proxies, due to the obvious run-time creation-of-proxy performance gains.

The link actually shows an Auditing app example.

丶情人眼里出诗心の 2024-08-15 09:04:07

请查看这篇文章。作者在 NHibernate 中使用 ProxyFactoryFactory(好听的名字=))的概念来实现实体类的自定义代理。

可以设置 ProxyFactoryFactory 类型 通过配置或在代码中。

也许这会解决你的任务。

Have a look at this post. Author uses notion of ProxyFactoryFactory (nice name =)) in the NHibernate to implement custom proxies for entity classes.

it is possible to set ProxyFactoryFactory type through configuration or at code.

Maybe this will solve your task.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文