【问题标题】:NHibernate mapping domain "extension properties"?NHibernate 映射域“扩展属性”?
【发布时间】:2010-08-01 11:08:13
【问题描述】:

我想“扩展”我的域类,而不必向域类本身添加数据。考虑我有以下课程:

public class Person
{
public virtual int Id { get; private set; }
public virtual string Name { get; set; }
}

我在数据库中有下表:

tblPersons
---------------
Id integer 
Name varchar(50)
CreatedBy varchar(50)
CreatedDate datetime

所以我不想在我的域类中添加“CreatedBy”和“CreatedDate”,因为这与实际域本身无关......

是否有可能在我加载实体时获取这些数据?我想这样使用它:

Person person = session.Load<Person>(1);

person.CreatedBy(); <-- CreatedBy is an Extension function
person.CreatedDate(); <-- CreatedDate is an Extension function

谁能指点我要实现这个目标的方向?

我想过以下几种可能:

  • 实现一个自定义 ProxyFactory,我在其中注入一个自定义“接口”,例如 IUpdateable,但是 NHibernate 似乎没有一致地创建代理,有时它会加载我的“代理类”类,有时它会加载“普通班”:

    Person person = session.Load<Person>(2); //this will load my Proxy class of Person just fine
    
    Address address = person.Address; //Somehow this doesn't load a Proxy for Address, but instead loads it normally - seems like it's evaluating "ImmediateLoad", which doesn't load proxies, due to lazy loading... not sure how to make this behave as I want.
    
  • 使用自定义 PropertyAccessor。我已经读过一些关于这个的东西 - 但似乎我实际上必须将它映射到一个在域类上退出的属性......这样就行不通了,对吧?

  • 就像 NHibernate 在创建 Proxy 类时向运行时“注入”代码一样 - 也许我也可以这样做,但将“接口”注入到原始 Person 类中?

【问题讨论】:

  • 不使用 NHiberante 时,扩展方法如何工作?
  • 好吧,正如主题所暗示的那样,我确实使用 NHibernate。我已经用“NHibernate Fluent”映射了 Person.Name 属性,以匹配数据库中的 tblPersons.Name。对我来说,这不是 c# “扩展函数”的问题......这是我如何添加映射 Person 类的 NHibernate 以加载 CreatedDate / CreatedBy 但将这些值放在一些外部结构或其他东西中......这就是什么我不知道怎么解决。谢谢,
  • 没有 NHiberante 做不到的事情,用 NHibernate 做不到。

标签: c# nhibernate proxy nhibernate-mapping mapping


【解决方案1】:

您可以使用基类或组件映射轻松做到这一点。我不会为此目的使用扩展方法。我使用基类:

public abstract class Auditable : IAuditable
{
    public virtual string CreatedBy { get; set; }
    public virtual DateTime CreatedDate { get; set; }
}

public class Person : Auditable {}

流畅的映射:

public class AuditableClassMap<T> : ClassMap<T> where T: IAuditable
{
    public AuditableClassMap()
    {
        Map(x => x.CreatedBy);
        Map(x => x.CreatedDate);
    }
}

public class PersonMap : AuditableClassMap<Person> {}

如果您坚持将审计属性排除在类之外,您可以将审计属性映射为一个组件。

【讨论】:

  • 很好,谢谢 - 我真的无法更改域类,但是正如你所说 - 我不介意以其他方式映射它。您能解释一下将审计属性映射为一个组件会有什么帮助吗?我认为“组件映射”只是将扁平数据库列分组到域类中更深层次结构的一种方式? - 我将阅读 Nhibernate 中的组件。谢谢您的帮助! :)
  • 如果您不能更改域类,那么我看不到任何合理的方法来实现这一点。
【解决方案2】:

这是一个想法。我从来没有实现过这个,所以在你测试它之前,请谨慎对待它。

创建一个不同的类来封装Person -- PersonCreation 或其他东西的审计数据。

给它一个标识符,一个创建日期和创建者属性,以及Person id 的属性(我认为不需要实际引用Person,除非标识符是非公开的,在这种情况下您可能需要一个WeakReference,这样您就不会在应用程序的整个生命周期内将每个Person 实例都保留在内存中)。

您需要为 NHibernate 创建一个映射以从 Person 表中获取 PersonCreation 对象。

从这里,您可以简单地让扩展方法在调用时获取数据。根据您的使用情况,这可能合理也可能不合理。您必须每次都创建一个新会话或同步一个静态会话。

或者……

在包含CreatedBy() 和CreatedDate() 扩展方法的static 类中,创建一个静态IDictionary&lt;int, PersonCreation&gt; 来保存每个Person 的详细信息。由于创建数据可能是不可变的,因此我们不必担心它会变得陈旧。

您需要使用 Person 查询批量查询 PersonCreation。例如,您可以执行以下操作:

var creation = session.CreateCriteria<PersonCreation>()
    .Add(Restrictions.Eq("PersonId", 1))
    .Future<PersonCreation>();

var person = session.CreateCriteria<Person>()
    .Add(Restrictions.IdEq(1))
    .UniqueResult<Person>();

通过调用Future&lt;T&gt;(),您是在告诉 NHibernate 在会话已经进入数据库之前不要执行该查询。

获得结果后,您可以获取第一个创建结果并将其添加到字典中(以便扩展方法可以访问它),然后返回人员。

当您调用person.CreatedDate() 时,该方法可以使用传递的Person 参数的id 或Person 本身从字典中提取数据。

【讨论】:

  • 嘿,杰,谢谢! - 我肯定会玩这个想法,非常感谢! :)
猜你喜欢
  • 2015-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 1970-01-01
  • 2023-03-26
相关资源
最近更新 更多