C# 动态可交换数据访问层

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

我正在编写一个数据驱动的WPF客户端。客户端通常会从查询SQL db的WCF服务中提取数据,但我希望可以选择直接从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<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()类型的方法,以便可以将对象从本地生成的命名空间映射到常规项目命名空间,然后再映射回来

我将实施选项1——选项2肯定会起作用,但这是一种非常缓慢的方式。有时,当您告诉VS在生成代理时重用引用的类型时,它仍然会生成DTO的本地定义-在这种情况下,您可以进入生成的
Reference.cs
类文件并删除所有定义,然后继续使用在常规项目命名空间中定义的版本


除了WCF问题外,您似乎走上了正确的道路。

您已经有了一个非常灵活的软件开发方法的良好开端。您的方法已经遇到了主要问题:您的数据提供程序契约(
icCustomerFacade
)必须指定所有实现者都使用的数据对象。SQL和WCF数据提供程序都必须返回相同的数据对象

你贴上“这太可怕”标签的那部分?事实上并没有那么糟糕。您迭代了两次,是的,但这样做是为了提供更强大、更灵活的软件体系结构。性能不会那么差(除非您对列表中的许多项进行迭代),并且您的系统将能够在调用web服务和直接调用SQL server之间随意切换(无论这通常是否是一个好主意)

要消除双重迭代,可以做的一件事是让数据契约依赖于数据对象的抽象。例如,他们会返回
iccustomer
,而不是
Customer
。然后,SQL Server对象和WCF数据对象可以是完全不同的对象,只要它们实现了
ICCustomer
等接口

其他建议:

    您应该考虑返回代码< ILIST(或者甚至<代码> iQueabd),而不是“集合返回方法>代码>列表<代码>。<李>
  • 你们的工厂模式是一个良好的开端,但工厂是如此的落后您可能需要考虑进入完全依赖注入路径;我建议大家团结一致

  • 我个人认为,如果你正在谈论.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();
        }
    }