动态可交换数据访问层
我正在编写一个数据驱动的WPF客户端。 客户端通常从WCF服务中提取数据,该服务查询SQL数据库,但我希望选择直接从SQL或其他任意数据源提取数据。
我想出了这个设计,并希望听听你对它是否是最好的设计的看法。
首先,我们要从SQL中提取一些数据对象。
// The Data Object with a single property public class Customer { private string m_Name = string.Empty; public string Name { get { return m_Name; } set { m_Name = value;} } }
然后我计划使用所有数据访问层应该实现的接口。 假设一个人也可以使用抽象类。 思考?
// The interface with a single method interface ICustomerFacade { List GetAll(); }
可以创建SQL实现。
// Sql Implementation public class SqlCustomrFacade : ICustomerFacade { public List GetAll() { // Query SQL db and return something useful // ... return new List(); } }
我们还可以创建一个WCF实现。 WCF的问题在于它不使用相同的数据对象。 它创建了自己的本地版本,因此我们必须以某种方式复制细节。 我想可以使用reflection来复制相似字段的值。 思考?
// Wcf Implementation public class WcfCustomrFacade : ICustomerFacade { public List GetAll() { // Get date from the Wcf Service (not defined here) List wcfCustomers = wcfService.GetAllCustomers(); // The list we're going to return List customers = new List(); // This is horrible foreach(WcfService.Customer wcfCustomer in wcfCustomers) { Customer customer = new Customer(); customer.Name = wcfCustomer.Name; customers.Add(customer); } return customers; } }
我还计划使用工厂来决定使用哪个立面。
// Factory pattern public class FacadeFactory() { public static ICustomerFacade CreateCustomerFacade() { // Determine the facade to use if (ConfigurationManager.AppSettings["DAL"] == "Sql") return new SqlCustomrFacade(); else return new WcfCustomrFacade(); } }
这就是通常使用DAL的方式。
// Test application public class MyApp { public static void Main() { ICustomerFacade cf = FacadeFactory.CreateCustomerFacade(); cf.GetAll(); } }
我感谢你的想法和时间。
您有一个非常好的开始,一个非常灵活的软件方法。 您已经遇到了主要问题:数据提供者合同( ICustomerFacade
)必须指定所有实施者使用的数据对象。 SQL和WCF数据提供程序都必须返回相同的数据对象。
那部分你标记为“这太可怕了”? 实际上并不是那么糟糕。 你正在迭代两次,是的,但是你这样做是为了提供更强大,更灵活的软件架构。 性能不会那么糟糕(除非你迭代列表中的很多项),你的系统将能够在调用Web服务和直接调用SQL服务器之间切换(一般来说这是不是一个好主意)随意。
消除双重迭代可以做的一件事是让数据合同依赖于数据对象的抽象。 例如,他们会返回ICustomer
而不是Customer
。 然后,您的SQL Server对象和您的WCF数据对象可以完全不同,只要它们实现了ICustomer
等接口。
其他建议:
- 你应该考虑为你的集合返回方法返回
IList
(甚至是IEnumerable
)而不是List
。 - 你的工厂模式是一个良好的开端,但工厂是如此的2000年代。 :)你可能想考虑使用完整的dependency injection路由; 我建议在Microsoft企业库中使用 Unity。
有两种方法可以解决WCF实现中的数据对象与数据存储区返回的数据对象之间的差异:
-
在创建WCF代理时,请确保重用引用程序集中的所有类型 (如果使用VS选项而不是直接调用svcutil,则在“高级”对话框中)。
-
在DTO(数据对象)上有一个Clone()或CopyFrom()类型方法,以便您可以将对象从本地生成的命名空间映射到常规项目命名空间,然后再返回
我会实现选项1 – 选项2肯定会工作,但这是一个非常慢的方法。 有时,当您在生成代理时告诉VS重用引用的类型时,它仍会生成DTO的本地定义 – 在这种情况下,您只需进入生成的Reference.cs
类文件并删除所有定义,然后继续使用常规项目命名空间中定义的版本。
除了WCF问题,您似乎走在了正确的轨道上。
我个人认为如果你在谈论.NET到.NET,svcutil.exe是一个反模式。 这是一个没有实际价值的额外突破点。 如果您正在与外部服务或不同平台集成,则svcutil.exe是一个不错的选择。
通常,对于每个服务,应该有一个额外的Contracts程序集,其中包含服务的所有服务接口和datacontracts。 该程序集由服务和客户端引用。 这样,当进行更改时,它们将反映在客户端和服务器中。
http://blog.walteralmeida.com/2010/08/wcf-tips-and-tricks-share-types-between-server-and-client.html