3

我正在创建 n 层应用程序架构。不同的层对彼此的内部实现一无所知,层之间的通信通过非常狭窄的接口处理,并辅以 IoC/DI。

现在我将业务对象(在业务层中定义)传递给数据层。业务层本身不知道数据的实际保存方式和位置(通常是数据库,但业务层不应该知道)。业务对象通过 IDataReader 的实现传递到数据层(这种方法还支持在未来的场景中批量加载数据)。数据层从 IDataReader 读取所有数据并调用一些存储过程将数据保存到数据库(如果保存一个对象,IDataReader 返回“一行”)。

实际问题在这里:

因为我只是将 IDataReader 传递给数据层并将数据与其类型断开连接,所以在这种情况下确定数据位置的最佳方法是什么?

例如,如果我将“用户”类型的实际业务对象传递给数据层,那么数据层应该将数据保存到表“用户”中。在其他一些情况下,数据可能会独立于业务层中的类型保存到一些不同的结构中。

在当前实现中,我将业务对象的类型信息传递到数据层,数据层检查此类型并决定将数据放置在何处。

数据层检查传入数据并确定其位置是正确的解决方案,还是数据层应该公开可以保存数据的“位置”列表(枚举?)?

提前致谢!

/澄清

我在这里看到的选项是: 1. 数据层给出可以保存数据的“plces”列表 2. 数据层检查给定的参数(如类型 arg)并决定存储数据的位置

第一选择惩罚;如果我尝试将“产品”类型的业务对象存储到“用户”类型通常使用的结构中怎么办?

第二选择罚分;我必须将类型“Namespace1.Namespace2.User”映射到将其数据保存到表“User”的特定例程。所以手动为每种类型做一些映射......

/澄清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) 数据结构自动。因为这种数据结构可能存在一些性能问题,数据层必须有办法将特定的业务对象类型保存在自己专用的数据结构中(通常是与该类型一一映射的表)。

这里的想法是,我可以创建许多新的业务对象,并且可以将它们全部保存到数据层,而无需实际对数据层进行任何编码!以后如果需要,我可以为选定的业务对象创建自己的专用数据结构。

4

2 回答 2

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();

在这些示例中,数据层创建并填充业务对象。否则,业务层必须知道表列名称。

(注:我这里不是指具体的数据接口。)


更新:

如果您想创建自己的与业务层断开连接的数据库层,您还可以引入带有合同的单独程序集

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());

现在,您的数据层可以与客户一起工作,而无需了解您的客户类别,也无需参考业务层程序集。

于 2012-03-18T19:52:17.397 回答
1

我建议您使用 ORM(实体框架,NHibernate)或微 ORM(PetaPoco,Dapper)将您的对象映射到数据存储。
如果您有具体问题,请查看并拍摄。

更新:我想我刚刚得到了你的要求。
您需要在数据层中为每种类型定义一个新方法。所以:

public User GetUserById(int id);
public void SaveUser(User user);
public Product GetProductById(int id);
public void SaveProduct(Product product);
于 2012-03-18T19:43:00.043 回答