这里的实体类更倾向于数据传输对象(既DTO)。无论是编码风格采用 事务脚本 还是 领域模型,我们都会遇到各种各样的数据传输对象,尤其是传统事务脚本三层架构的编码中,更会遇到各类实体对象,一般来说,这些实体对象产生的原因如下:

1:为各类报表和查询服务的联表查询,会导致字段变多,带来的实体的属性增多。怎么办,创造新的实体类或者为原有实体类新增字段?

2:前台不同的需求场合,会构建不同的 DTO 对象(如JSON对象)传递到后台,新的对象产生就创造新的实体类或者为原有实体类新增字段?

我们大多会遇到以上这类问题。以下是避免创建新的实体类或者为原有实体类新增字段的一些措施。

先来看第一种情况。

一:联表查询中的字段增多

这是从里(数据层)发散到外(UI层)的过程。

以往我们像这样编码:

public override IList<User> GetList()
{
    string sql = "select * from [EL_Organization].[User] where state=1";
    var ds = SqlHelper.ExecuteDataset(
        SqlHelper.ConnectionString,
        CommandType.Text,
        sql);
    return DataTableHelper.ToList<User>(ds.Tables[0]);
}

现在,我们利用匿名类型:

public IEnumerable GetList2()
{
    string sql = "select * from [EL_Organization].[User] where state=1";
    var ds = SqlHelper.ExecuteDataset(
        SqlHelper.ConnectionString,
        CommandType.Text,
        sql);

var oblist = new List<object>();
    foreach (DataRow row in ds.Tables[0].Rows)
    {
        oblist.Add(new { Id = row["Id"], Name = row["Name"] });
    }

return oblist;
}

你可能注意到两点变化,

第一:我们原先使用泛型+反射的方法(通用方法,不赘述),直接返回了 IList<User>,而现在,我们没有这样的通用方法了,只能通过一个 foreach 循环自己来构建这样的匿名类型及其列表。你可能会首先担心循环中的那些代码繁琐而机械,但是这一定比创建一个新类型来的简单。其次,你可能会想到改造原先的泛型+反射方法,使其支持匿名类型,但当我写完这个函数的时候,我有点担心其效率,所以我仍旧推荐上面的写法。

第二点变化:返回类型是一个 IEnumerable 了,替代了原先的 IList<User>。这仿佛牺牲了一些原先作为强类型的特性,但这些特性是可克服的。有一种做法是,将返回类型修改为 IList<dynamic>,不过这仍旧带来一点点性能损耗,因此我仍旧建议,如无特殊必要(如:在业务层需要对返回结果进行赋值),返回 IEnumerable 已足够。

现在,Dal 层已经是这样,上次调用者该如何用,以 MVC 中的控制器为例,我们应该如下使用(备注,下面这个方法针对是上层返回类型是一个 IEnumerable ,如果返回 List<dynamic>,则参考“ExpandoObject对象的JSON序列化” ):

public JsonResult xTest()
{
    UserDal dal = new UserDal();
    var list = dal.GetList2();
    return this.Json(list, JsonRequestBehavior.AllowGet);
}

你可能会觉得,这太简单,直接从 DAL 层取出来,就丢给前台了。没错,在事务脚本编码时,很多时候就是这么简单,即便仍旧要对 DAL 返回值做特殊处理,采用匿名类型也不会阻止我们什么事情。

二:构建不同的对象(如JSON对象)传递到后台

我们知道,MVC 中的控制器,如果参数中带了强类型的参数,则 MVC 引擎会自动前台 post 过来的 JSON 对象转换为该强类型。如,我们后台是这样的(即,在参数中声明了强类型):

public class xTemp
{
    public string XId { get; set; }
    public string XName { get; set; }
}

public JsonResult xTest(xTemp SomeData)
{
    。。。
    return this.Json(easyUiPages, JsonRequestBehavior.AllowGet);
}

以及前台是这样的:

var SomeData = {
    "xId": "xxx",
    "xName": "zzz"
};
$.ajax({
    type: "post",
    data: SomeData,
    url: "@ViewBag.Domain/home/xTest",
    success: function (data) {
        ;
    }
});

则我们的后台一定会解析得到这个对象。但是,如果我们将控制器中的 SomeData的声明换成了 object 或者 dynamic,则我们什么也不会得到。所以,如果不想创建新的类型,则有集中做法:

1:一一获得对象的属性

直接传递或再创建 dynamic 对象,然后将其传递到 bll 或者 dal 层进行处理;一般要处理的对象属性少于3个,可这样处理。

2:或者,还是老老实实创建实体吧

传统我们至少有三种选择:创建 ViewModel 或 领域实体 或 数据实体。

2.1ViewModel 是指在 UI 层的实体,默认在 UI 层创建一个 ViewModel 的文件夹进行放置,这些实体不发散到其它层。当然,如果一定要发散到下层,可以传递 dynamic;

2.2 领域实体,则指在业务逻辑层的实体,或者我们也称之为业务实体。业务实体和业务类并行放置一起,上层(如 UI 层)可访问,下层不可访问;

2.3 数据实体,则指最底层的,连 DAL 层都能访问的实体,一般用于映射数据库表(联表则使用导航属性,如 EntityFramework 等使用的),但一些通用的实体类,也可放置在此层。备注:也可以将领域实体作为数据实体;

在一些小型应用中,往往 ViewModel 、领域实体、数据实体,统一归并到实体层。总之,实体层的创建和放置必须非常明确,随意创建并且随意放置的实体类,会导致代码膨胀并给重构带来灾难。

如果我们发现数据实体已经不够用,这里建议的路线图是:

1:修改数据实体或创建新的数据实体;

2:如果数据实体不能动,或不想动,则创建 ViewModel;

3:如果发现业务类需要用到该实体,则把该 ViewModel 重构为 领域实体;

4:如果发现该实体要传递到 DAL 层,那么我们有四种选择,

4.1 手动转为数据实体;

4.2 回到第一步,将实体重构为数据实体;

4.3 使用 dynamic 传递到 Dal 层;

4.4 将属性作为参数传递;

创建多余的实体的做法,可以看到我们啰啰嗦嗦讲了这么多,如果你已经觉得很烦了,或者觉得自己根本掌握不了这个度,那么我们的终极做法是下面的这个做法。

3:接受 JSON 字符串,反序列化为 dynamic

上面我们说到:将控制器中的 SomeData的声明换成了 object 或者 dynamic,则我们什么也不会得到。但是,我们可以这么做,

前台的 data: SomeData ,换为:

data: "someData=" + JSON.stringify(SomeData)

注意,因为我们这里实际传递的是字符串,所以不能声明:

contentType: "application/json; charset=utf-8",

后台则为:

[SessionFilter]
public JsonResult XTest(string someData)
{
    var jsSerializer = new JavaScriptSerializer();
    var model = jsSerializer.Deserialize(somData, typeof(dynamic)) as dynamic;
    //如果是列表,则像如下处理
    //var models = jsSerializer.Deserialize(somData, typeof(List<dynamic>)) as List<dynamic>;

省略
    return this.Json(result, JsonRequestBehavior.DenyGet);
}

这是建议的、减少实体类型的行之有效的方法。

三:另一种思路:构建通用的实体类

该思路的中心思想就是:消灭所有的实体类,任何传统的实体无非就是:类型名+属性名+属性值,于是,我们就构建这样的一个通用实体类,类似:

[Serializable]
public sealed class DynamicDalObject : DynamicObject, IDictionary<string, object>
{
    public DynamicDalObject()
    {
        this._inner = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
    }

public DynamicDalObject(IEnumerable<KeyValuePair<string, object>> keyValuePairs) : this()
    {
        foreach (var keyValuePair in keyValuePairs)
        {
            this._inner.Add(keyValuePair);
        }
    }

……
}

然后,发散到 DAL 层,就可以进行这样的操作:

public static int Update(bool isOnline, int viewdCount, string Id)
{
    using (var manger = new DynamicDalSqlManager())
    {
        return
            manger.DataAccess.Update(
                new DynamicDalObject(
                    new[]
                        {
                            new KeyValuePair<string, object>("id", Id),
                            new KeyValuePair<string, object>("IsOnline", isOnline),
                            new KeyValuePair<string, object>("ViewdCount", viewdCount),
                        }),
                "EL_Course.CourseHistory",
                new[] { "id" });
    }
}

优点:

1:只要不想用实体类,就用它解决;

2:可构建通用的 Dal,即,DAl 只要一个也就够了;

缺点:

1:失去了面向对象结构,实际上变成了面向 SQL 编码;

2:不停的拆箱、装箱;

这种通用实体类的做法,在一些业务相对单一,可尝试使用,能带来短平快的效果。

四:总结

总之,应充分利用 匿名类型 和 dynamic 类型来减少无必要的或者模棱两可的实体类的创建,最后,再明确一下建议的架构思路:

1:首先我们有数据实体层,该实体层可拓展;

2:若现有实体不能满足需要,则从 DAL 到 UI,可使用匿名类型;

3:若现有实体不能满足需要,则从 客户端 到 控制器,可 JSON 字符串(非对象),在控制器中反序列化为 dynamic 类型;

4:最后,如发现某个业务方法被多个场景使用,可再将其 dynamic 对象重构成一个 数据实体(优先) 或 领域实体。为什么数据实体优先呢,因为从业务层传递到 DAL 层,我们可以直接传递该强类型对象。

5:在领域模型中,DTO 对象适用于本建议。

减少到处衍生的实体类相关推荐

  1. 掌握 ASP.NET 之路:自定义实体类简介

    发布日期 : 5/24/2005| 更新日期 : 5/24/2005 Karl Seguin Microsoft Corporation 摘要:有些情况下,非类型化的 DataSet 可能并非数据操作 ...

  2. 掌握 ASP.NET 之路:自定义实体类简介 来源 :msdn

    ADODB.RecordSet 和常常被遗忘的 MoveNext 的时代已经过去,取而代之的是 Microsoft ADO.NET 强大而又灵活的功能.我们的新武器就是 System.Data 名称空 ...

  3. CN.Text开发笔记—利用反射将数据读入实体类

    在实际开发中,我们经常需要从数据库中读取数据并赋值给实体类的相应属性.在.Text的DataDTOProvider中存在大量这样的代码, 比如: public Role[] GetRoles(int  ...

  4. 浅谈三层架构中的实体类(C#)

    最近因为三层架构中的实体类,引发了不少小问题,下面列举一下,谈谈自己的感想. 本文所指的实体类仅限于三层中的实体类,即数据库表的映射. 一.为什么要用实体类? |  使程序简洁易懂,便于维护. |  ...

  5. 实体类(VO,DO,DTO)的划分

    经常会接触到VO,DO,DTO的概念,本文从领域建模中的实体划分和项目中的实际应用情况两个角度,对这几个概念进行简析. 得出的主要结论是:在项目应用中,VO对应于页面上需要显示的数据(表单),DO对应 ...

  6. netbeans连接数据库_NetBeans Java EE技巧#1 –数据库中的实体类

    netbeans连接数据库 NetBeans IDE是开发各种应用程序的绝佳选择. 具体来说,我每天都使用它来开发和维护Java EE应用程序. 在过去的几个发行版中,不仅Java EE的生产力提高了 ...

  7. NetBeans Java EE技巧#1 –数据库中的实体类

    NetBeans IDE是开发各种应用程序的绝佳选择. 具体来说,我每天都使用它来开发和维护Java EE应用程序. 在过去的几个发行版中,不仅Java EE的生产力提高了,而且NetBeans ID ...

  8. json字符串生成C#实体类的工具

    转载:http://www.cnblogs.com/finesite/archive/2011/07/31/2122984.html json作为互联网上轻量便捷的数据传输格式,越来越受到重视.但在服 ...

  9. JSON C# Class Generator ---由json字符串生成C#实体类的工具

    json作为互联网上轻量便捷的数据传输格式,越来越受到重视.但在服务器端编程过程中,我们常常希望能通过智能提示来提高编码效率.JSON C# Class Generator 能将json格式所表示的J ...

最新文章

  1. java int转String全部方式的效率对照与深入解析
  2. 并发编程(一)__volatile关键字
  3. roads 构筑极致用户体验_智美双极 引领旗舰 亚洲龙探索革新的高品质体验
  4. vue - webpack.dev.conf.js
  5. Windows API ——GetLogicalDriveStrings——获取逻辑驱动器
  6. UI-148xLE-M相机参数
  7. 计算机复试面试基础知识(八股文)(数据库、数据结构、操作系统、计网、机组等)
  8. TMS320F28035 中断中使用DINT,无法关闭中断的原因
  9. 14寸M1Pro-Max芯片款MAC安装Photoshop2021/2022安装教程硬核分享和激 活方式
  10. 如何正确使用 Mac 电脑的“恢复模式”?
  11. java高校墨香文学社管理系统计算机毕业设计MyBatis+系统+LW文档+源码+调试部署
  12. minigui 的中文字体部署及支持窗口模态、非模态
  13. ftime()函数的用法!
  14. 单向链表与双向链表的区别
  15. IE、FireFox都支持的收藏本站代码
  16. htmla标签下划线去除_html超链接的下划线怎么去掉?a标签去下划线的方法都在这里...
  17. ES6中的字符串API.md
  18. php printer使用手册,go/printer
  19. 基金|最新“情绪领域”项目情报分享,速看
  20. 30天自制操作系统:第三天 进入32位模式并导入C语言

热门文章

  1. mysql安装1335_Mysql 安装问题。提示MySQL Server 5.1 -- Error 1335.
  2. 计算机二级语义网络的研究现状与展望,计算机二级access选择题题库研究.doc
  3. 预编码 matlab,无线通信-预编码-MATLAB代码合集
  4. es if语法 script_熬夜7天,我总结了JavaScript与ES的25个重要知识点!
  5. python垃圾回收价格表_深度解析Python垃圾回收机制(超级详细)
  6. 怎么往integer型数组添加数据_面试中经常问到的Redis七种数据类型,你都真正了解吗?...
  7. django批量修改table_Django 数据库表多对多的创建和增删改查
  8. 二进制编译安装mysql_MariaDB通用二进制编译安装详解
  9. ip转换软件在五八上能用吗?_交换机能当路由器用吗?浅谈交换器和路由器的区别...
  10. 字符和编码之间的转换(Python)