NHibernate映射域“扩展属性”?

时间:2010-08-01 11:08:14

标签: c# nhibernate proxy nhibernate-mapping mapping

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

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。我已经阅读了一些关于此的内容 - 但似乎我必须将其实际映射到域类上的EXITS属性...这样就行不通了,对吧?

  • 正如NHibernate在创建Proxy类时“注入”代码到运行时一样 - 也许我可以这样做但是将“接口”注入到原来的Person类中?

2 个答案:

答案 0 :(得分: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> {}

如果您坚持要将审计属性保留在类之外,则可以将审计属性映射为组件。

答案 1 :(得分:0)

这是一个想法。我从来没有实现过这个,所以在你测试它之前先拿一点盐。

创建一个不同的类,用于封装Person - PersonCreation或其他内容的审核数据。

为它提供标识符,创建日期和created-by属性,以及Person id的属性(我看不需要实际引用Person,除非标识符是非公开的,在这种情况下,您可能需要WeakReference,因此在应用程序的生命周期内不会将每个Person实例保留在内存中。

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

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

或者...

在包含staticCreatedBy()扩展方法的CreatedDate()课程中,创建一个静态IDictionary<int, PersonCreation>来保存每个Person的详细信息。由于创建数据可能是不可改变的,因此我们不必担心这种情况会变得陈旧。

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

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

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

通过调用Future<T>(),您告诉NHibernate不要执行该查询,直到会话已经转到数据库。

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

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