ExtJS4.1+MVC3+Spring.NET1.3+EF5 整合七:数据传输对象

1 DTO、Form的划分

开讲之前先看如下图示:


其中,Dao层与EF框架、Service与Dao层之间的传输都是以Model、SQL(仅在分页操作)传递,Action与Service是以DTO和ISQLPaging接口传递的,而View(本项目是ExtJS)与Action之间传递有两种情况,一是Action传递给ExtJS,另一种是ExtJS请求数据给Action。

先说前一种情况,由于ExtJS一般是接受JSON或XML数据,所以在Action中就不能使用ViewData、ViewBag或TempData简单的传递了,因为ExtJS得不到,而要在Action中使用JSON方法,把一个class转换成JSON(或XML)对象返回给客户端。因为,Service传递给Action的是Model、IList<Model>对象,所以就需要把Model转换为JSON,我的办法是先把Model转移成DTO,然后用Json(DTO)方法返回JSON对象。

再来看后一种情况,这个比较好实现,为Action指定参数或实体类,MVC会自动绑定。在这里,我为Action指定Form类型参数,这样我可以在Form中编写验证方法,比如验证用户请求的数据是否合法。在领域模型设计中,DTO是不允许这么做的,DTO只允许包含属性,属于贫血。这也是我把Form从DTO中脱离出来的原因,如果把项目分的太细就显得太复杂了,所以,在企业级的开发中,请不要这么设计。另外,ASP.NET MVC中可以通过特性来验证Model,之前我在项目中也曾这么做过,但也遇到一些问题,比如:用户在注册和修改资料时,Model的所有属性并不是都输入的,当时的做法是创建两个Model,一个是UserRegister,一个是UserUpdateData,显示不合理。

看下最后的设计:


此时,就遇到了class之间的映射(转换)问题,在java开发中有BeanUtils.copyProperties和PropertyUtils.copyProperties方法实现对象之间的属性复制,但在.net类库中是没有相似的类的,但庆幸的是,已经有第三方公司实现了此功能 -- AutoMapper。


2 AutoMapper

网上已有不少文章说了AutoMapper的使用,这里我也提下几种常用的情况。

在使用前先到官方网站下载最新版(http://automapper.codeplex.com/releases),并引入到项目中(本项目中需要引入的是Web和Service两个)

2.1 简单映射

    public class UploadDTO
    {
        public string Code { get; set; }
        public string Name { get; set; }
        public short IsRequired { get; set; }
        public short FileType { get; set; }
        public short IsSave { get; set; }
        public string Extension { get; set; }
        public string SavePath { get; set; }
        public long MaxSize { get; set; }
        public string ParentPattern { get; set; }
    }
    
    public partial class Upload
    {
        public string Code { get; set; }
        public string Name { get; set; }
        public short IsRequired { get; set; }
        public short FileType { get; set; }
        public short IsSave { get; set; }
        public string Extension { get; set; }
        public string SavePath { get; set; }
        public long MaxSize { get; set; }
        public string ParentPattern { get; set; }
    }

    Mapper.CreateMap<UploadDTO, Upload>();
    var dto = new UploadDTO();
    dto.Code = '10';
    dto.Name = 'test';
    var entity = Mapper.Map<UploadDTO, Upload>(dto);

这么看简单吧,就是把AddressDto实例所有属性复制到Address实体类中。

2.2 属性是class的映射

    public class AdminDTO 
    {
        public string Code { get; set; }
        public string Password { get; set; }
        public string Name { get; set; }
        public DateTime AddTime { get; set; }
        public DateTime? LastTime { get; set; }
        public string LastIP { get; set; }
        public short ErrorCount { get; set; }
        public short State { get; set; }
        public string RoleCode { get; set; }
        public string RoleName { get; set; }
    }
    public partial class Admin
    {
        public string Code { get; set; }
        public string Password { get; set; }
        public string Name { get; set; }
        public System.DateTime AddTime { get; set; }
        public Nullable<System.DateTime> LastTime { get; set; }
        public string LastIP { get; set; }
        public short ErrorCount { get; set; }
        public short State { get; set; }
        public virtual Role Role { get; set; }
    }
    
    var map = Mapper.CreateMap<Admin, AdminDTO>();
    map.ForMember(e => e.RoleCode, m => m.MapFrom(f => f.Role.Code));
    map.ForMember(e => e.RoleName, m => m.MapFrom(f => f.Role.Name));
    
    Admin entity = null;//假设这里不是null,实际是个Model实例
    var dto = Mapper.Map<Admin, AdminDTO>(entity);

其他的情况请查询相关的网站,接下来看下DTO、Form中的定义。


3 DTO

为了方便,我把暂时用到的DTO放在一起:

    public class UploadDTO
    {
        public string Code { get; set; }
        public string Name { get; set; }
        public short IsRequired { get; set; }
        public short FileType { get; set; }
        public short IsSave { get; set; }
        public string Extension { get; set; }
        public string SavePath { get; set; }
        public long MaxSize { get; set; }
        public string ParentPattern { get; set; }
    }
    public class RoleDTO
    {
        public string Code { get; set; }
        public string Name { get; set; }
        public short State { get; set; }
        public short Sort { get; set; }
        public IList<CategoryDTO> Categories { get; set; }
    }
    public class AdminDTO 
    {
        public string Code { get; set; }
        public string Password { get; set; }
        public string Name { get; set; }
        public DateTime AddTime { get; set; }
        public DateTime? LastTime { get; set; }
        public string LastIP { get; set; }
        public short ErrorCount { get; set; }
        public short State { get; set; }
        public string RoleCode { get; set; }
        public string RoleName { get; set; }
    }
    public class AuthorizeDTO
    {
        public string RoleCode { get; set; }
        public IList<string> CategoryCodes { get; set; }
    }
    public class CategoryDTO
    {
        public string Code { get; set; }
        public string Name { get; set; }
        public string English { get; set; }
        public string ParentCode { get; set; }
        public string ParentName { get; set; }
        public string UploadCode { get; set; }
        public string UploadName { get; set; }
        public short IsPage { get; set; }
        public short IsMenu { get; set; }
        public short IsMap { get; set; }
        public short EnableConsult { get; set; }
        public string PageUrl { get; set; }
        public string MenuUrl { get; set; }
        public short Sort { get; set; }

        public string iconCls { get; set; }
        public bool leaf { get; set; }
        public bool expanded { get; set; }
        public IList<object> children { get; set; }
    }

4 Form

    public abstract class FormBase
    {
        public string id { get; set; }
        public int page { get; set; }
        public int limit { get; set; }

        public int PageIndex
        {
            get
            {
                return (page - 1) < 0 ? 0 : (page - 1);
            }
        }
        public int PageSize
        {
            get
            {
                return limit <= 0 ? 20 : limit;
            }
        }
        public int RecordCount { get; set; }

        public string Escape(string value)//SQL数据替换
        {
            if (String.IsNullOrEmpty(value))
                return value;

            return value.Replace("\'", "\'\'").Replace("%", "");
        }

        public bool CheckRegex(string str, string pattern, bool isRequired)//正则表达式校验
        {
            return CheckRegex(str, pattern, RegexOptions.IgnoreCase, isRequired);
        }
        public bool CheckRegex(string str, string pattern, RegexOptions options, bool isRequired)
        {
            Regex regex = new Regex(pattern, options);
            return regex.IsMatch(str);
        }

        public bool CheckCount(string str, int length, bool isRequired)//字符个数校验
        {
            return CheckCount(str, length, length, isRequired);
        }
        public bool CheckCount(string str, int? minLength, int? maxLength, bool isRequired)
        {
            if (String.IsNullOrEmpty(str))
                return !isRequired;

            int length = str.Length;
            if (minLength.HasValue && length < minLength.Value)
                return false;
            if (maxLength.HasValue && length > maxLength.Value)
                return false;

            return true;
        }

        public bool CheckLength(string str, int length, bool isRequired)//字符长度(双字节算2个)校验
        {
            return CheckLength(str, length, length, isRequired);
        }
        public bool CheckLength(string str, int? minLength, int? maxLength, bool isRequired)
        {
            if (String.IsNullOrEmpty(str))
                return !isRequired;

            int length = Encoding.Default.GetByteCount(str);
            if (minLength.HasValue && length < minLength.Value)
                return false;
            if (maxLength.HasValue && length > maxLength.Value)
                return false;

            return true;
        }

        public bool CheckDateTime(DateTime? dt, DateTime? start, DateTime? stop, bool isRequired)//时间校验
        {
            if (!dt.HasValue)
                return !isRequired;

            if (start.HasValue && dt.Value < start.Value)
                return false;
            if (stop.HasValue && dt.Value > stop.Value)
                return false;

            return true;
        }

        public bool CheckInteger(int? value, int? minValue, int? maxValue, bool isRequired)//整型数据校验
        {
            if (!value.HasValue)
                return !isRequired;

            if (minValue.HasValue && value.Value < minValue.Value)
                return false;
            if (maxValue.HasValue && value.Value > maxValue.Value)
                return false;

            return true;
        }

        public bool CheckDouble(double? value, double? minValue, double? maxValue, bool isRequired)//双精度数据校验
        {
            if (!value.HasValue)
                return !isRequired;

            if (minValue.HasValue && value.Value < minValue.Value)
                return false;
            if (maxValue.HasValue && value.Value > maxValue.Value)
                return false;

            return true;
        }
    }
    public class RoleForm : FormBase, ISQLPaging
    {
        public string Code { get; set; }
        public string Name { get; set; }
        public short State { get; set; }
        public short Sort { get; set; }

        public string QuerySQLWhere { get; set; }
        public string QuerySQL
        {
            get
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("SELECT * FROM Role WHERE 1=1 ");
                if (!String.IsNullOrEmpty(this.Code))
                {
                    sb.Append("AND Code='" + base.Escape(this.Code) + "' ");
                }
                if (!String.IsNullOrEmpty(this.Name))
                {
                    sb.Append("AND Name LIKE '%" + base.Escape(this.Name) + "%' ");
                }
                if (!String.IsNullOrEmpty(this.QuerySQLWhere))
                {
                    sb.Append(this.QuerySQLWhere);
                }
                sb.Append(" ORDER BY Code ASC");

                return sb.ToString();
            }

        }

        public bool Validation()
        {
            return base.CheckLength(this.Code, 2, true)
                    && base.CheckLength(this.Name, 2, 20, true);
        }
        public bool ValidationDelete()
        {
            return base.CheckLength(this.Code, 2, true);
        }
    }
    public class AdminForm : FormBase, ISQLPaging
    {
        public string Code { get; set; }
        public string Password { get; set; }
        public string Name { get; set; }
        public DateTime AddTime { get; set; }
        public DateTime? LastTime { get; set; }
        public string LastIP { get; set; }
        public short ErrorCount { get; set; }
        public short State { get; set; }
        public string RoleCode { get; set; }

        public string QuerySQLWhere { get; set; }
        public string QuerySQL
        {
            get
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("SELECT * FROM Admin WHERE 1=1 ");
                if (!String.IsNullOrEmpty(this.Code))
                {
                    sb.Append("AND Code='" + base.Escape(this.Code) + "' ");
                }
                if (!String.IsNullOrEmpty(this.Name))
                {
                    sb.Append("AND Name LIKE '%" + base.Escape(this.Name) + "%' ");
                }
                if (!String.IsNullOrEmpty(this.QuerySQLWhere))
                {
                    sb.Append(this.QuerySQLWhere);
                }
                sb.Append(" ORDER BY Code ASC");

                return sb.ToString();
            }
        }

        public bool ValidationAdd()
        {
            return base.CheckLength(this.Code, 5, 20, true)
                    && base.CheckLength(this.Password, 5, 20, true)
                    && base.CheckLength(this.Name, 2, 20, true)
                    && base.CheckLength(this.RoleCode, 2, true);
        }
        public bool ValidationUpdate()
        {
            return base.CheckLength(this.Code, 5, 20, true)
                    && base.CheckLength(this.Password, 5, 20, false)
                    && base.CheckLength(this.Name, 2, 20, true)
                    && base.CheckLength(this.RoleCode, 2, true);
        }
        public bool ValidationData()
        {
            return base.CheckLength(this.Code, 5, 20, true)
                    && base.CheckLength(this.Password, 5, 20, false)
                    && base.CheckLength(this.Name, 2, 20, true);
        }
        public bool ValidationDelete()
        {
            return base.CheckLength(this.Code, 5, 20, true);
        }
    }
    public class UploadForm : FormBase
    {
        public string Code { get; set; }
        public string Name { get; set; }
        public short IsRequired { get; set; }
        public short FileType { get; set; }
        public short IsSave { get; set; }
        public string Extension { get; set; }
        public string SavePath { get; set; }
        public long MaxSize { get; set; }
        public string ParentPattern { get; set; }
    }
    public class AuthorizeForm : FormBase
    {
        public string RoleCode { get; set; }
        public string[] CategoryCodes { get; set; }

        public bool Validation()
        {
            if (!base.CheckLength(this.RoleCode, 2, true))
                return false;

            if (this.CategoryCodes != null && this.CategoryCodes.Length > 0)
            {
                foreach (var code in this.CategoryCodes)
                {
                    if (!base.CheckLength(code, 2, 20, true))
                        return false;
                }
            }

            return true;
        }
    }
    public class CategoryForm : FormBase
    {
        public string Code { get; set; }
        public string Name { get; set; }
        public string English { get; set; }
        public string ParentCode { get; set; }
        public string UploadCode { get; set; }
        public short IsPage { get; set; }
        public short IsMenu { get; set; }
        public short IsMap { get; set; }
        public short EnableConsult { get; set; }
        public string PageUrl { get; set; }
        public string MenuUrl { get; set; }
        public short Sort { get; set; }

        public bool Validation()
        {
            return base.CheckLength(this.Code, 2, 20, true)
                    && base.CheckLength(this.Name, 2, 20, true)
                    && base.CheckLength(this.English, null, 20, false)
                    && base.CheckLength(this.ParentCode, 2, 20, false)
                    && base.CheckLength(this.UploadCode, 2, 20, false)
                    && base.CheckLength(this.PageUrl, null, 250, false)
                    && base.CheckLength(this.MenuUrl, null, 250, false)
                    && base.CheckInteger(this.Sort, -1000, 1000, true)
                    && (
                        String.IsNullOrEmpty(this.ParentCode)
                        ? this.Code.Length == 2
                        : this.Code.Substring(0, this.ParentCode.Length) == this.ParentCode
                    );
        }
        public bool ValidationDelete()
        {
            return base.CheckLength(this.Code, 2, 20, true);
        }
    }

代码有些多,下一篇做完基本的ExtJS DEMO后,我将第一个版本的源码,请关注。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值