C# 动态可交换数据访问层
我正在编写一个数据驱动的WPF客户端。客户端通常会从查询SQL db的WCF服务中提取数据,但我希望可以选择直接从SQL或其他任意数据源提取数据 我想出了这个设计,想听听你对它是否是最好的设计的意见 首先,我们要从SQL中提取一些数据对象C# 动态可交换数据访问层,c#,wcf,reflection,oop,polymorphism,C#,Wcf,Reflection,Oop,Polymorphism,我正在编写一个数据驱动的WPF客户端。客户端通常会从查询SQL db的WCF服务中提取数据,但我希望可以选择直接从SQL或其他任意数据源提取数据 我想出了这个设计,想听听你对它是否是最好的设计的意见 首先,我们要从SQL中提取一些数据对象 // The Data Object with a single property public class Customer { private string m_Name = string.Empty; public string Nam
// 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<Customer> GetAll();
}
// Wcf Implementation
public class WcfCustomrFacade : ICustomerFacade
{
public List<Customer> GetAll()
{
// Get date from the Wcf Service (not defined here)
List<WcfService.Customer> wcfCustomers = wcfService.GetAllCustomers();
// The list we're going to return
List<Customer> customers = new List<Customer>();
// This is horrible
foreach(WcfService.Customer wcfCustomer in wcfCustomers)
{
Customer customer = new Customer();
customer.Name = wcfCustomer.Name;
customers.Add(customer);
}
return customers;
}
}
这就是DAL通常的使用方式
// Test application
public class MyApp
{
public static void Main()
{
ICustomerFacade cf = FacadeFactory.CreateCustomerFacade();
cf.GetAll();
}
}
感谢您的想法和时间。有两种方法可以解决WCF实现中的数据对象与从数据存储返回的内容之间的差异:
- 创建WCF代理时,请确保重用引用程序集中的所有类型(如果使用VS选项而不是直接调用svcutil,则在“高级”对话框中)
- 在DTO(数据对象)上具有Clone()或CopyFrom()类型的方法,以便可以将对象从本地生成的命名空间映射到常规项目命名空间,然后再映射回来
Reference.cs
类文件并删除所有定义,然后继续使用在常规项目命名空间中定义的版本
除了WCF问题外,您似乎走上了正确的道路。您已经有了一个非常灵活的软件开发方法的良好开端。您的方法已经遇到了主要问题:您的数据提供程序契约(
icCustomerFacade
)必须指定所有实现者都使用的数据对象。SQL和WCF数据提供程序都必须返回相同的数据对象
你贴上“这太可怕”标签的那部分?事实上并没有那么糟糕。您迭代了两次,是的,但这样做是为了提供更强大、更灵活的软件体系结构。性能不会那么差(除非您对列表中的许多项进行迭代),并且您的系统将能够在调用web服务和直接调用SQL server之间随意切换(无论这通常是否是一个好主意)
要消除双重迭代,可以做的一件事是让数据契约依赖于数据对象的抽象。例如,他们会返回iccustomer
,而不是Customer
。然后,SQL Server对象和WCF数据对象可以是完全不同的对象,只要它们实现了ICCustomer
等接口
其他建议:
- 你们的工厂模式是一个良好的开端,但工厂是如此的落后您可能需要考虑进入完全依赖注入路径;我建议大家团结一致
我个人认为,如果你正在谈论.net到.NET,那么SvCuTiel.EXE是一个反模式。这是一个额外的断点,没有真正的价值。如果要与外部服务或其他平台集成,svcuti.exe是一个不错的选择 通常,对于每个服务,都应该有一个额外的契约程序集,其中包含服务的所有服务接口和数据契约。服务和客户端都引用此程序集。这样,当进行更改时,它们将同时反映在客户端和服务器中
正如@TomTom所强调的,Linq在SQL façade中生成业务对象和查询时可以节省大量时间。本例中的对象仅用于说明概念。请查看,谢谢您的评论。选项1听起来好像可以解决问题!非常有用的评论。非常感谢你。
// 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();
}
}
// Test application
public class MyApp
{
public static void Main()
{
ICustomerFacade cf = FacadeFactory.CreateCustomerFacade();
cf.GetAll();
}
}