【问题标题】:Data transfer object pattern数据传输对象模式
【发布时间】:2013-02-06 08:30:17
【问题描述】:

对不起,我是企业应用程序和设计模式的新手。可能是这个问题缺乏对设计模式的了解。我发现使用 DTO 传输数据更好。

我的业务实体类如下:

public class Patient
{    
    public string ID { get; set; }
    public string FullName { get; set; }
    public string FirstName { get; set; }
    public string Surname { get; set; }
}

所以在我的应用程序中,用户只提供 ID 和 HospitalID。所以它调用另一个 Web 服务并获取人员信息

 public class PersonDTO
 {
     public string NIC { get; set; }
     public string FullName { get; set; }
     public string FirstName { get; set; }
     public string BirthPlace { get; set; }
     public string BirthCertificateID { get; set; }
 }

因此,基于这些信息,我将前往 Patient 对象。 (使用 DTO 模式)

所以我想写一个新的类来转换它如下。

public class PatientDO
{
    public static Patient ConvertToEntity(
        PatientRegistrationDTO pregDTO,
        PersonDTO person
    )
    {
        Patient p = new Patient();
        p.NIC = pregDTO.NIC;
        p.FullName = person.FullName;
        p.FirstName = person.FirstName;
        return p;
    }
}

但最近我读了很少的articles ,他们使用了Serializer Helper class 以及XmlSerializer,我不明白他们为什么使用这样的东西。

对于DTO模式是说需要使用XmlSerializer,为什么要使用它?

【问题讨论】:

    标签: c# .net design-patterns dto


    【解决方案1】:

    你真的应该看看 AutoMapper。

    http://automapper.org

    这是一款可以包含在解决方案中的软件,它会自动将值从一个类映射到另一个类。

    它会自动映射具有相同名称的属性,并且在涉及子对象时也非常聪明。但是,它还可以在您需要时提供完整的映射控制。

    编辑

    几个示例来展示 AutoMapper 的工作原理。请注意,在现实生活中我永远不会这样编码。简洁!

    示例类。

    // Common scenario.  Entity classes that have a connection to the DB.
    namespace Entities 
    {
       public class Manager
       {
          public virtual int Id { get; set; }
          public virtual User User { get; set; }
          public virtual IList<User> Serfs { get; set; }
       }
    
       public class User
       {
          public virtual int Id { get; set; }
          public virtual string Firstname { get; set; }
          public virtual string Lastname { get; set; }
       }
    }
    
    
    
    // Model class - bit more flattened
    namespace Models 
    {
       public class Manager 
       {
          public int Id { get; set; }
          public string UserFirstname { get; set; }
          public string UserLastname { get; set; }
          public string UserMiddlename { get; set; }
       }
    }
    

    通常,您需要在项目中配置所有自动映射。通过我刚刚给出的示例,您可以像这样配置 Entities.Manager 和 Models.Manager 之间的映射:-

    // Tell AutoMapper that this conversion is possible
    Mapper.CreateMap<Entities.Manager, Models.Manager>();
    

    然后,在您的代码中,您将使用类似这样的东西从实体版本中获取一个新的 Models.Manager 对象。

    // Map the class
    var mgr = Map<Entities.Manager, Models.Manager>
      ( repoManager, new Models.Manager() );
    

    顺便说一句,如果你命名一致,AM 足够聪明,可以自动解析许多属性。

    上面的例子,应该自动填充 UserFirstname 和 UserLastname,因为:-

    • Manager 有一个名为 User 的属性
    • 用户拥有名为 Firstname 和 Lastname 的属性

    但是,在 Entities.Manager 和 Models.Manager 之间进行映射操作后,Models.Manager 中的 UserMiddlename 属性将始终为空,因为 User 没有名为 Middlename 的公共属性。

    【讨论】:

    • 请注意,您确实需要查看性能注意事项。您可以使用 AutoMapper。不应该。
    • imo,我从 AutoMapper 看到的大多数性能问题都来自定义不明确的映射(由我编写!)。我遇到的最大问题是 AutoMapper 爬取 nHibernate 对象图并进行大量 DB 调用。
    • 这就是为什么我赞成你回答。但是,正如他所说的他是新人,我只想指出这是一个很好的方法,但没有严格的要求。
    • 这可能是一本关于 automapper devtrends.co.uk/blog/…的很好读物
    • 虽然我没有亲自使用过这个,但是这个使用 Linq 查询的自动投影可能会给你一个想法。 lostechies.com/jimmybogard/2011/02/09/…
    【解决方案2】:

    CodeProject 中有一个不错但简单的演示。值得通过它。 新手可以初步了解设计 DTO。

    http://www.codeproject.com/Articles/8824/C-Data-Transfer-Object

    以下是内容摘要:

    数据传输对象“DTO”是一个简单的可序列化对象,用于跨应用程序的多个层传输数据。 DTO 中包含的字段通常是原始类型,例如字符串、布尔值等。其他 DTO 可能包含或聚合在 DTO 中。例如,您可能有一个包含在 LibraryDTO 中的 BookDTO 集合。我创建了一个由多个应用程序使用的框架,该框架利用 DTO 跨层传输数据。该框架还依赖于其他 OO 模式,例如 Factory、Facade 等。与 DataSet 相比,DTO 的一大优点是 DTO 不必直接匹配数据表或视图。 DTO 可以聚合来自另一个 DTO 的字段

    这是所有数据传输对象的基类。

    using System;
    
    namespace DEMO.Common
    {
    /// This is the base class for all DataTransferObjects.
        public abstract class DTO
        {
            public DTO()
            {
            }
        }
    }
    

    这是 DTO 的派生类:

    using System;
    using System.Xml.Serialization;
    using DEMO.Common;
    
    namespace DEMO.DemoDataTransferObjects
    {
    public class DemoDTO : DTO
    {
        // Variables encapsulated by class (private).
        private string demoId = "";
        private string demoName = "";
        private string demoProgrammer = "";
    
        public DemoDTO()
        {
        }
    
        ///Public access to the DemoId field.
        ///String
        [XmlElement(IsNullable=true)]
        public string DemoId
        {
            get
            {
                return this.demoId;
            }
            set
            {
                this.demoId = value;
            }
        }
    
        ///Public access to the DemoId field.
        ///String
        [XmlElement(IsNullable=true)]
        public string DemoName
        {
            get
            {
                return this.demoName;
            }
            set
            {
                this.demoName = value;
            }
        }
    
        ///Public access to the DemoId field.
        ///String
        [XmlElement(IsNullable=true)]
        public string DemoProgrammer
        {
            get
            {
                return this.demoProgrammer;
            }
            set
            {
                this.demoProgrammer = value;
            }
        }
    
    }
    

    这是 DTO 的辅助类。它具有序列化和反序列化 DTO 的公共方法。

    using System;
    using System.Xml.Serialization;
    using System.IO;
    
    namespace DEMO.Common
    {
    public class DTOSerializerHelper
    {
        public DTOSerializerHelper()
        {
        }
    
        /// 
        /// Creates xml string from given dto.
        /// 
        /// DTO
        /// XML
        public static string SerializeDTO(DTO dto)
        {
            try
            {
                XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
                StringWriter sWriter = new StringWriter();
                // Serialize the dto to xml.
                xmlSer.Serialize(sWriter, dto);
                // Return the string of xml.
                return sWriter.ToString();
            }
            catch(Exception ex)
            {
                // Propogate the exception.
                throw ex;
            }
        }
    
        /// 
        /// Deserializes the xml into a specified data transfer object.
        /// 
        /// string of xml
        /// type of dto
        /// DTO
        public static DTO DeserializeXml(string xml, DTO dto)
        {
            try
            {
                XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
                // Read the XML.
                StringReader sReader = new StringReader(xml);
                // Cast the deserialized xml to the type of dto.
                DTO retDTO = (DTO)xmlSer.Deserialize(sReader);
                // Return the data transfer object.
                return retDTO;
            }
            catch(Exception ex)
            {
                // Propogate the exception.
                throw ex;
            }            
        }
    
    }
    

    现在开始序列化/反序列化:

    using System;
    using DEMO.Common;
    using DEMO.DemoDataTransferObjects;
    
    namespace DemoConsoleApplication
    {
    public class DemoClass
    {
        public DemoClass()
        {
        }
    
        public void StartDemo()
        {
            this.ProcessDemo();
        }
    
        private void ProcessDemo()
        {
            DemoDTO dto = this.CreateDemoDto();
    
            // Serialize the dto to xml.
            string strXml = DTOSerializerHelper.SerializeDTO(dto);
    
            // Write the serialized dto as xml.
            Console.WriteLine("Serialized DTO");
            Console.WriteLine("=======================");
            Console.WriteLine("\r");
            Console.WriteLine(strXml);
            Console.WriteLine("\r");
    
            // Deserialize the xml to the data transfer object.
            DemoDTO desDto = 
              (DemoDTO) DTOSerializerHelper.DeserializeXml(strXml, 
              new DemoDTO());
    
            // Write the deserialized dto values.
            Console.WriteLine("Deseralized DTO");
            Console.WriteLine("=======================");
            Console.WriteLine("\r");
            Console.WriteLine("DemoId         : " + desDto.DemoId);
            Console.WriteLine("Demo Name      : " + desDto.DemoName);
            Console.WriteLine("Demo Programmer: " + desDto.DemoProgrammer);
            Console.WriteLine("\r");
        }
    
        private DemoDTO CreateDemoDto()
        {
            DemoDTO dto = new DemoDTO();
    
            dto.DemoId            = "1";
            dto.DemoName        = "Data Transfer Object Demonstration Program";
            dto.DemoProgrammer    = "Kenny Young";
    
            return dto;
        }
    }
    

    最后这段代码在主应用程序中执行

    static void Main(string[] args)
    {
        DemoClass dc = new DemoClass();
        dc.StartDemo();
    }
    

    【讨论】:

      【解决方案3】:

      XmlSerializer 或 JsonSerializer 可用于从源(Web 服务)序列化(加载)XML 或 Json 数据。或解释 DTO 的名称:您将数据从源(Web 服务)序列化(传输)到(通用 DTO)对象。所以 DTO 是通用对象。有时,制作尽可能宽的 DTO 对象并完全填充它是很聪明的,这样您就可以从该对象中使用您喜欢的任何内容并将其复制到您“自己的”程序对象中。

      示例:我开发了一个显示交通导航数据的程序。我在 DTO 对象中序列化整个 xml 或 json 消息。在这个 DTO 对象中包含更多信息,然后我将在我的程序中需要它并且它可以采用不同的形式,所以我将只使用需要的东西。 DTO 对象使从源(Web 服务)中提取数据变得更加容易。

      由于名称为“Auto”,我不想使用 AutoMapper。我想知道我在做什么,想知道我的数据要去哪里。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-07-11
        • 2011-10-22
        • 2012-09-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-29
        相关资源
        最近更新 更多