动态可交换数据访问层

时间:2010-05-07 12:16:23

标签: c# wcf reflection oop polymorphism

我正在编写一个数据驱动的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<Customer> GetAll();
}

可以创建SQL实现。

// Sql Implementation
public class SqlCustomrFacade : ICustomerFacade
{
    public List<Customer> GetAll()
    {
        // Query SQL db and return something useful
        // ...

        return new List<Customer>();
    }
}

我们还可以创建WCF实现。 WCF的问题在于它不使用相同的数据对象。它创建了自己的本地版本,因此我们必须以某种方式复制细节。我想可以使用反射来复制相似字段的值。想法?

// 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;
    }
}

我还计划使用工厂来决定使用哪个立面。

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

感谢您的想法和时间。

3 个答案:

答案 0 :(得分:4)

您可以通过非常灵活的软件方法开始。您已经遇到了主要问题:数据提供者合同(ICustomerFacade)必须指定所有实施者使用的数据对象。 SQL和WCF数据提供程序都必须返回相同的数据对象。

那部分你标注为“这太可怕了”?实际上并不是那么糟糕。你正在迭代两次,是的,但是你这样做是为了提供更强大,更灵活的软件架构。性能不会 错误(除非您在列表中迭代许多项),并且您的系统将能够在调用Web服务和直接调用SQL服务器之间切换(无论是否一般来说这是一个好主意)。

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

其他建议:

  • 您应该考虑返回IList(甚至是IEnumerable)而不是List来收集回收方法。
  • 你的工厂模式是一个良好的开端,但工厂是如此。 :)您可能要考虑使用完整的依赖注入路由;我在Microsoft Enterprise Library
  • 中建议使用Unity

答案 1 :(得分:1)

有两种方法可以解决WCF实现中的数据对象与数据存储区返回的数据对象之间的差异:

  • 创建WCF代理时,请确保重用引用程序集中的所有类型(如果使用VS选项而不是直接调用svcutil,则在“高级”对话框中)。

  • 在DTO(数据对象)上有一个Clone()或CopyFrom()类型方法,这样您就可以将对象从本地生成的命名空间映射到常规项目命名空间,然后再返回

    < / LI>

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

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

答案 2 :(得分:0)

如果你在谈论.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