代码之家  ›  专栏  ›  技术社区  ›  André Haupt saber safavi

动态可交换数据访问层

  •  3
  • André Haupt saber safavi  · 技术社区  · 16 年前

    我正在编写一个数据驱动的WPF客户机。客户机通常会从查询SQL数据库的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();
    }
    

    可以创建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 回复  |  直到 11 年前
        1
  •  4
  •   Randolpho    16 年前

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

    你把那部分贴上“这很可怕”的标签?其实也没那么糟。您重复了两次,是的,但这样做是为了提供一个更强大、更灵活的软件体系结构。性能将不会 那个 坏的(除非您在列表中迭代了许多项),您的系统将能够在任意调用Web服务和直接调用SQL Server之间进行切换(无论这是否是一个好主意)。

    为了消除双重迭代,您可以做的一件事是让数据契约依赖于数据对象的抽象。他们会回来的 ICustomer 而不是 Customer 例如。那么,只要SQL Server对象和WCF数据对象实现了 重症监护室 等接口。

    其他建议:

    • 你应该考虑回来 IList (甚至 IEnumerable )而不是 List 为您的收集返回方法。
    • 您的工厂模式是一个很好的开始,但工厂是如此的2000。:)您可能要考虑采用完全依赖注入路径;我建议在 Microsoft Enterprise Library .
        2
  •  1
  •   slugster Joey Cai    16 年前

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

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

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

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

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

        3
  •  0
  •   Jason Turan    11 年前

    我个人认为,如果您正在与.NET对话,svcutil.exe是一种反模式。这是一个没有实际价值的额外突破点。如果要与外部服务或其他平台集成,则svcutil.exe是一个不错的选择。

    通常,对于每个服务,都应该有一个额外的契约程序集,其中包含服务的所有服务接口和数据契约。服务和客户端都引用了此程序集。这样,当进行更改时,它们将同时反映在客户机和服务器中。

    http://blog.walteralmeida.com/2010/08/wcf-tips-and-tricks-share-types-between-server-and-client.html