我正在创建n层应用程序架构。不同的层不知道彼此的内部实现是什么,层之间的通信是通过IoC / DI辅助的非常窄的接口来处理的。
现在我将业务对象(在业务层中定义)传递给数据层。业务层本身并不知道数据实际保存的方式和位置(通常是数据库,但业务层不应该知道)。业务对象通过IDataReader的实现传递到数据层(此方法还支持在未来场景中批量加载数据)。数据层从IDataReader读取所有数据并调用一些存储过程将数据保存到数据库(如果保存了一个对象,IDataReader将返回“一行”)。
实际问题在于:
因为我只是将IDataReader传递给数据层并将数据与其类型断开连接,在这种情况下,确定数据位置的最佳方法是什么?
示例如果我将“User”类型的实际业务对象传递给数据层,则数据层应将数据保存到表“User”中。在某些其他情况下,数据可能会保存到某个不同的结构中,与业务层中的类型无关。
在当前实现中,我将业务对象的类型信息传递到数据层,数据层检查此类型并确定数据的放置位置。
数据层检查传入数据并确定其位置是正确的解决方案还是数据层应该公开可以保存数据的“位置”列表(枚举?)?
提前致谢!
/澄清:
我在这里看到的选项是: 1.数据层给出了可以保存数据的“plces”列表 2.数据层检查给定的参数(如类型arg)并决定存储数据的位置
首选罚款;如果我尝试将“Product”类型的业务对象存储到通常由“User”类型使用的结构中,该怎么办
第二选择罚款;我必须将类型“Namespace1.Namespace2.User”映射到将其数据保存到表“User”的特定例程。所以手动为EACH类型做一些映射...
/澄清2:
现在我这样检索:
service.Retrieve(typeof(Catalog), null, catalogArgs, e => catalogConverter.Read(e));
所以我将typeof(Catalog)传递给数据层...所以我在数据层中有类型信息。
现在在数据层我需要选择“适配器”,它可以很难从数据库中获取数据。我可以编写巨大的if / switch结构来选择适配器......这令人沮丧。我也可以写属性并像这样使用它:
[TypeAdapterAttribute("Namespace1.Namespace2.Catalog, and assembly info...")]
class CatalogAdapter { ... }
然后我有代码从给定类型映射到属性值...
...但是这个硬编码类型的字符串有点膨胀并且有问题...
有任何建议......?
/澄清3
我知道这个系统可以通过“可插拔的业务模块”进行扩展。这些模块包含基本业务逻辑不知道的业务对象(和一些逻辑),数据层也完全不知道“插入的程序集”中包含的这些业务对象。此外部业务模块未引用基础业务层或数据层。保存来自此外部程序集的业务对象(=发送到数据层)时,数据层默认将其保存为EAV样式(http://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80% 93value_model)数据结构自动生成。由于这种数据结构可能存在一些性能问题,因此数据层必须能够将特定业务对象类型保存在自己的专用数据结构中(通常是与该类型一对一映射的表)。所以问题来了,如何实现这个“选择决策”:)
这里的想法是我可以创建许多新的业务对象,我可以将它们全部保存到数据层,而无需实际编写任何数据层代码!以后我可以根据需要为选定的业务对象创建自己的专用数据结构。
答案 0 :(得分:1)
我建议您使用ORM(Entitiy Framework,NHibernate)或micro-ORM(PetaPoco,Dapper)将对象映射到数据存储。
如果你有一个特定的问题,请查看并拍摄。
更新:我想我得到了你所要求的东西 您需要在数据层中为每种类型定义新方法。 所以:
public User GetUserById(int id);
public void SaveUser(User user);
public Product GetProductById(int id);
public void SaveProduct(Product product);
答案 1 :(得分:1)
如果要创建与业务层断开连接的自己的数据库层,还可以引入具有合同的单独程序集
List<Customer> customers = DB.LoadCustomers();
数据层可以使用泛型类型参数,并通过Reflection
获取有关业务对象的信息。这提供了层的良好分离,因为数据层不需要引用业务组件。
List<Customer> customers = DataContext.Query<Customer>.Load();
或
Customer customer = DataContext.Query<Customer>.Load(custID);
O / R-mappers通常像这样工作
List<Customer> customers = Context.Query<Customer>()
.Where(cust => cust.Name.StartsWith("A"))
.OrderBy(cust => cust.Name)
.ToList();
在这些示例中,数据层创建并填充业务对象。否则,业务层必须知道表列名。
(注意:这里我没有提到具体的数据接口。)
更新:
如果要创建自己的业务层diconnected数据库层,您还可以引入一个单独的程序集与合同
public interface ICustomer
{
string LastName { get; set; }
string FirstName { get; set; }
...
}
数据层和业务层都会引用这些合同。
在数据层中,您将拥有类似于
的方法public List<T> LoadAll<T>(Func<T> create)
{
var list = new List<T>();
if (T is ICustomer) {
string sql = "SELECT * FROM tblCustomer";
...
while (reader.NextResult()) {
ICustomer cust = (ICustomer)create();
cust.FirstName = reader.GetString("FirstName");
...
list.Add((T)cust);
}
} else if (T is IOrder) {
...
}
return list;
}
在业务层中,您将编写
List<ICustomer> customers = DbLayer.LoadAll<ICustomer>(() => new Customer());
现在,您的数据层可以与客户合作,而无需了解您的客户类,也无需参考业务层程序集。