我目前处于多个相当复杂的系统的设计阶段,这些系统具有共同的功能(例如,它们都具有客户关系管理(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相应地实施工厂,分别创建ACustomers或BCustomers。
这是我的意思的UML图(应用程序B未显示):
对于持久性我使用NHibernate。 A和B都提供自己的映射(按代码映射)以包含额外的属性。此外,A将IACustomer定义为ACustomer的代理类型,B将IBCustomer定义为BCustomer的代理类型。
我现在可以使用NHibernate来处理A和B中的实体,例如在A
session.QueryOver<ACustomer>()
.Where(c=>c.ReceivesNewsletter)
.List()
现在假设我想在基础库中对客户做一些事情(例如在某种服务对象中)。我刚刚制作了一个非常简单的原型,到目前为止,这似乎工作正常:
session.QueryOver<ICustomer>()
.Where(c => c.CustomerNumber == "1234ABC")
.List()
也就是说,我可以在QueryOver中使用特定实体的代理类型的基类,并且NHibernate会创建正确的查询,例如在A:
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)]
这些查询是否始终按预期工作?我是否可以在基础库中的查询中始终安全地使用基本类型的代理接口? NHibernate会不会总是找到“正确的”实体类型和表来检索?或者是否会出现这种影响查询效率的情况,而不是b / c NHibernate需要做猜测工作?在这种情况下我应该注意哪些其他陷阱?
我在文档中找不到相关信息。这种方法可以让我巧妙地将某些域的公共部分移动到他们自己的基础库中,但我想确保它有效。
答案 0 :(得分:1)
我认为这种情况没有问题。 特别是因为每个应用程序中只有一个ICustomer实现。
即使你的每个应用程序都有多个实现,你也可能会遇到一些按id加载的问题(session.Load(42),因为根据你的映射,可能有多个具有该id的客户)。但收到客户名单的查询仍然有效。
当我在过去查看与你的NHibernate类似的问题时,我读了这篇文章 - 它讨论了派生的基类而不是界面,但它是同一个想法:http://codebetter.com/jameskovacs/2011/02/16/getload-polymorphism-in-nhibernate-3/
NHibernate没有猜测工作 - 在初始化时,它构建了一个存储它对任何给定类型的所有映射,当你为任何类型的类型编写查询时,它会找到它从中继承的正确类型并相应地进行查询。