C# 我可以使用实体的基本类型安全地进行查询吗';NHibernate中的代理接口?

C# 我可以使用实体的基本类型安全地进行查询吗';NHibernate中的代理接口?,c#,nhibernate,C#,Nhibernate,我目前正处于多个相当复杂的系统的设计阶段,这些系统共享相同的功能(例如,两者都具有客户关系管理(CRM)和销售功能)。因此,我试图提取域的公共部分,并在两个应用程序中重用它 假设我有应用程序A和应用程序B,它们都使用CRM功能。在大多数情况下,CRM功能是相同的,但这两个应用程序都喜欢增强与CRM相关的一些功能 我想创建一个实现CRM系统基本版本的库,例如,将客户抽象为 interface ICustomer { string CustomerNumber {get;set;} } 基本库

我目前正处于多个相当复杂的系统的设计阶段,这些系统共享相同的功能(例如,两者都具有客户关系管理(CRM)和销售功能)。因此,我试图提取域的公共部分,并在两个应用程序中重用它

假设我有应用程序A和应用程序B,它们都使用CRM功能。在大多数情况下,CRM功能是相同的,但这两个应用程序都喜欢增强与CRM相关的一些功能

我想创建一个实现CRM系统基本版本的库,例如,将客户抽象为

interface ICustomer {
  string CustomerNumber {get;set;}
}
基本库具有ICustomer的基本实现

class Customer: ICustomer
应用程序A现在可以对此进行扩展:

interface IACustomer : ICustomer {
    bool ReceivesNewsletter {get;set;}
}

class ACustomer : Customer, IACustomer {
   ...
}
同样,B也有自己的变化:

interface IBCustomer : ICustomer {
    string NickName {get;set;}
}

class BCustomer : Customer, IBCustomer {
    ....
}
出于抽象的目的,我从不在基本库中实例化具体类型,而是使用工厂或DI容器,例如:

interface ICrmFactory {
    ICustomer CreateCustomer();
}
A和B相应地实施工厂,以便分别创建客户或B客户

下面是我的意思的UML图(未显示应用程序B):

对于持久性,我使用NHibernate。A和B都提供自己的映射(按代码映射)以包括额外的属性。此外,A将IACustomer定义为ACustomer的代理类型,B将IBCustomer定义为BCCustomer的代理类型

我现在可以使用NHibernate处理A和B中的实体,例如A中的实体

session.QueryOver<ACustomer>()
    .Where(c=>c.ReceivesNewsletter)
    .List()
我的问题 这些查询是否总是按预期工作?在基本库的查询中,我是否可以始终安全地使用代理接口的基本类型?NHibernate是否总能找到要检索的“正确”实体类型和表?或者在某些情况下,这会对查询效率产生负面影响b/c NHibernate需要进行猜测工作吗?在这种情况下,我还应该注意其他陷阱吗


我在文档中找不到这方面的信息。这种方法允许我将一些域的公共部分整齐地移动到它们自己的基本库中,但我希望确保它能正常工作。

我认为这种方案没有问题。 特别是因为在每个应用程序中,ICustomer只有一个实现

即使每个应用程序都有多个实现,按id加载也可能会遇到一些问题(session.Load(42),因为根据您的映射,可能有多个客户具有该id)。但查询以接收客户列表仍然有效

当我过去在NHibernate上研究类似于您的问题时,我读到了这篇文章——它讨论的是派生基类而不是接口,但想法是一样的:


NHibernate不进行猜测-在初始化时,它会为任何给定类型构建一个所有映射的存储,当您为任何类型编写查询时,它会找到从中继承的正确映射类型并进行相应的查询。

ACustomer&B Customer是如何映射的?它们是否使用任何继承映射策略进行映射?还是完全单独映射?他们彼此完全独立。事实上,应用程序A和B是完全独立的应用程序。另外,尽管ACustomer源于Customer,但只有ACustomer被映射,所以Customer/ACustomer不涉及继承映射。应用程序A中的所有客户都是敏锐者。感谢链接,我现在非常有信心我的想法会在实践中奏效。似乎只要没有歧义,我就可以查询继承链中的任何类型,NH将获取适当的实体。
session.QueryOver<ICustomer>()
   .Where(c => c.CustomerNumber == "1234ABC")
   .List()
SELECT
    this_.Id as Id0_0_,
    this_.CustomerNumber as Customer2_0_0_,
    this_.ReceivesNewsletter as Receives3_0_0_ 
FROM
    ACustomer this_ 
WHERE
    this_.CustomerNumber = @p0;
@p0 = '1234ABC' [Type: String (4000)]