NHibernate 映射域“扩展属性”?

发布于 2024-09-12 00:12:14 字数 1209 浏览 4 评论 0原文

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

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(2); //这将很好地加载我的 Person 代理类
    
    地址地址=人.地址; //不知何故,这不会加载地址代理,而是正常加载它 - 似乎它正在评估“ImmediateLoad”,由于延迟加载,它不会加载代理...不知道如何使其表现得像我一样想。
    
  • 使用自定义 PropertyAccessor。我已经读过一些有关此内容的内容 - 但似乎我实际上必须将其映射到域类上 EXITS 的属性...这样就行不通,对吗?

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

I would like to "extend" my domain classes without having to add data to the domain classes themselves. Consider I have the following class:

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

And I have the following table in the database:

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

So I don't want to add "CreatedBy" and "CreatedDate" to my domain class, because this has nothing to do with the actual domain itself...

Would it be possible to get this data whenever I load an entity? I would like to use it like this:

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

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

Can anyone point me in which direction to go in order to implement this?

I have thought about the following possibilities:

  • Implement a custom ProxyFactory, where I inject a custom "interface" such as IUpdateable, howver it seems like NHibernate doesn't create the proxies consistently, sometimes it loads a my "proxy class" class, and sometimes it loads the "normal class":

    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.
    
  • Using a custom PropertyAccessor. I have read something about this - but it seems I must actually map this to a property that EXITS on the domain class... so that wouldn't work, right?

  • Just as NHibernate "injects" code to the runtime when creating the Proxy classes - perhaps I could do the same but inject the "interface" to the original Person class instead?

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

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

发布评论

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

评论(2

爱的十字路口 2024-09-19 00:12:14

您可以使用基类或组件映射轻松地完成此操作。我不会为此目的使用扩展方法。我使用一个基类:

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> {}

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

You can easily do this using a base class or a component mapping. I would not use extension methods for this purpose. I use a base class:

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

public class Person : Auditable {}

Fluent mapping:

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

public class PersonMap : AuditableClassMap<Person> {}

If you are adamant about keeping audit properties out of your classes you could map the audit properties as a component.

┾廆蒐ゝ 2024-09-19 00:12:14

这是一个想法。我从未实现过这一点,所以在测试之前请持保留态度。

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

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

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

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

或者...

在包含 CreatedBy()CreatedDate() 扩展方法的 static 类中,创建一个静态 IDictionary 保存每个 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(),您可以告诉 NHibernate 在会话已经进入数据库之前不要执行该查询。

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

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

Here is one idea. I've never implemented this, so take it with a grain of salt until you've tested it.

Create a different class that encapsulates the audit data for Person -- PersonCreation or something.

Give it an identifier, a created date, and created-by property, and a property for the Person id (I see no need actually reference the Person, unless the identifier is non-public, in which case you may want a WeakReference so you don't keep every Person instance in memory for the life of the application).

You'll need to create a mapping for NHibernate to get PersonCreation objects from the Person table.

From here, you could simply have the extension methods fetch data when called. This may or may not be reasonable depending on your usage. You'll have to create a new session every time or synchronize a static session.

Or…

In the static class that contains your CreatedBy() and CreatedDate() extension methods, create a static IDictionary<int, PersonCreation> to hold the details for each Person. Since creation data is presumably immutable, we don't really have to worry about this becoming stale.

You'll want to batch queries for the PersonCreation with your Person queries. For example, you could do something like:

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

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

By calling Future<T>(), you're telling NHibernate not to execute that query until the session is already going to database anyway.

Once you get results, you can take the first creation result and add it to the dictionary (so the extension methods have access to it), and return the person.

When you call person.CreatedDate(), the method can just pull the data from the dictionary using the id of the passed Person paramater, or the Person itself.

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