最近在用entity framework 和 WCF结合做服务端,偶然发现一个问题,就是数据传输对象(DTO)的容量问题,我的项目方案是把数据访问层封装为WCF部署在外网服务器上供客户端调 用.我发现传输速度没有想象的那么好,简直就是不堪入目,终于有一天我发现问题的所在,就是edmx生成的实体类和自己手写实体类的区别,我用 District这张表来做演示,表中一共有5个字段,废话不多说,先看一代码,
下面是edmx自生成的District类代码
1 代码 2 3 [global::System.Data.Objects.DataClasses.EdmEntityTypeAttribute(NamespaceName="ExpressPlatformModel", Name="District")] 4 [global::System.Runtime.Serialization.DataContractAttribute(IsReference=true)] 5 [global::System.Serializable()] 6 public partial class District : global::System.Data.Objects.DataClasses.EntityObject 7 { 8 /// <summary> 9 /// 创建新的 District 对象。 10 /// </summary> 11 /// <param name="districtID">DistrictID 的初始值。</param> 12 /// <param name="cityID">CityID 的初始值。</param> 13 /// <param name="districtName">DistrictName 的初始值。</param> 14 public static District CreateDistrict(int districtID, int cityID, string districtName) 15 { 16 District district = new District(); 17 district.DistrictID = districtID; 18 district.CityID = cityID; 19 district.DistrictName = districtName; 20 return district; 21 } 22 /// <summary> 23 /// 架构中不存在属性 DistrictID 的注释。 24 /// </summary> 25 [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)] 26 [global::System.Runtime.Serialization.DataMemberAttribute()] 27 public int DistrictID 28 { 29 get 30 { 31 return this._DistrictID; 32 } 33 set 34 { 35 this.OnDistrictIDChanging(value); 36 this.ReportPropertyChanging("DistrictID"); 37 this._DistrictID = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value); 38 this.ReportPropertyChanged("DistrictID"); 39 this.OnDistrictIDChanged(); 40 } 41 } 42 private int _DistrictID; 43 partial void OnDistrictIDChanging(int value); 44 partial void OnDistrictIDChanged(); 45 /// <summary> 46 /// 架构中不存在属性 CityID 的注释。 47 /// </summary> 48 [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(IsNullable=false)] 49 [global::System.Runtime.Serialization.DataMemberAttribute()] 50 public int CityID 51 { 52 get 53 { 54 return this._CityID; 55 } 56 set 57 { 58 this.OnCityIDChanging(value); 59 this.ReportPropertyChanging("CityID"); 60 this._CityID = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value); 61 this.ReportPropertyChanged("CityID"); 62 this.OnCityIDChanged(); 63 } 64 } 65 private int _CityID; 66 partial void OnCityIDChanging(int value); 67 partial void OnCityIDChanged(); 68 /// <summary> 69 /// 架构中不存在属性 DistrictName 的注释。 70 /// </summary> 71 [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(IsNullable=false)] 72 [global::System.Runtime.Serialization.DataMemberAttribute()] 73 public string DistrictName 74 { 75 get 76 { 77 return this._DistrictName; 78 } 79 set 80 { 81 this.OnDistrictNameChanging(value); 82 this.ReportPropertyChanging("DistrictName"); 83 this._DistrictName = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value, false); 84 this.ReportPropertyChanged("DistrictName"); 85 this.OnDistrictNameChanged(); 86 } 87 } 88 private string _DistrictName; 89 partial void OnDistrictNameChanging(string value); 90 partial void OnDistrictNameChanged(); 91 /// <summary> 92 /// 架构中不存在属性 PinYin 的注释。 93 /// </summary> 94 [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute()] 95 [global::System.Runtime.Serialization.DataMemberAttribute()] 96 public string PinYin 97 { 98 get 99 { 100 return this._PinYin; 101 } 102 set 103 { 104 this.OnPinYinChanging(value); 105 this.ReportPropertyChanging("PinYin"); 106 this._PinYin = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value, true); 107 this.ReportPropertyChanged("PinYin"); 108 this.OnPinYinChanged(); 109 } 110 } 111 private string _PinYin; 112 partial void OnPinYinChanging(string value); 113 partial void OnPinYinChanged(); 114 /// <summary> 115 /// 架构中不存在属性 PostalCode 的注释。 116 /// </summary> 117 [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute()] 118 [global::System.Runtime.Serialization.DataMemberAttribute()] 119 public string PostalCode 120 { 121 get 122 { 123 return this._PostalCode; 124 } 125 set 126 { 127 this.OnPostalCodeChanging(value); 128 this.ReportPropertyChanging("PostalCode"); 129 this._PostalCode = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value, true); 130 this.ReportPropertyChanged("PostalCode"); 131 this.OnPostalCodeChanged(); 132 } 133 } 134 private string _PostalCode; 135 partial void OnPostalCodeChanging(string value); 136 partial void OnPostalCodeChanged(); 137 }
这是我手写的District类
1 代码 2 3 [DataContract] 4 [Serializable] 5 public class SDistrict 6 { 7 public SDistrict() { } 8 [DataMember] 9 private int districtID = 0; 10 11 public int DistrictID 12 { 13 get { return districtID; } 14 set { districtID = value; } 15 } 16 [DataMember] 17 private int cityID = 0; 18 19 public int CityID 20 { 21 get { return cityID; } 22 set { cityID = value; } 23 } 24 [DataMember] 25 private string districtName = string.Empty; 26 27 public string DistrictName 28 { 29 get { return districtName; } 30 set { districtName = value; } 31 } 32 [DataMember] 33 private string pinYin = string.Empty; 34 35 public string PinYin 36 { 37 get { return pinYin; } 38 set { pinYin = value; } 39 } 40 [DataMember] 41 private string postalCode = string.Empty; 42 43 public string PostalCode 44 { 45 get { return postalCode; } 46 set { postalCode = value; } 47 } 48 49 }
大家都看见了,edmx生成的和手写的District结构都是一模一样的,同样都有DataContract这个类属性,可以序列化和反序列化.下面是我Service中返回不同实体集合的一段代码,
自定义District类获取方法
1 代码 2 3 public List<SDistrict> initBuffByDistrict() //自己手写的实体类 4 { 5 6 using (ExpressPlatformEntities db = new ExpressPlatformEntities()) 7 { 8 9 List<District> result = db.District.ToList<District>(); 10 List<SDistrict> result1 = new List<SDistrict>(result.Count); 11 for (int i = 0; i < result.Count; i++) 12 { 13 SDistrict sd = new SDistrict(); 14 sd.DistrictID = result[i].DistrictID; 15 sd.DistrictName = result[i].DistrictName; 16 sd.CityID = result[i].CityID; 17 sd.PinYin = result[i].PinYin; 18 sd.PostalCode = result[i].PostalCode; 19 result1.Add(sd); 20 } 21 22 23 24 return result1; 25 }
edmx生成的District类获取方法
1 代码 2 3 public List<District> GetDistrictList() 4 { 5 using (ExpressPlatformEntities db = new ExpressPlatformEntities()) 6 { 7 return db.District.ToList(); 8 } 9 }
客户端使用http协议调用这两个方法的结果我用Fiddler测试工具抓取响应的消息所获得才恍 然大悟啊,请看下面
测试返回省市区表对象3304,以下是用entity framework 自生成的实体集合
==================================================================
Request Count: 1 //请求数
Bytes Sent: 1,090//发送字节数
Bytes Received: 2,462,366 //接收字节数
ACTUAL PERFORMANCE
--------------
Requests started at:10:24:09:1406 //请求开始
Responses completed at:10:24:17:5781 //响应返回
Aggregate Session time:00:00:08:4375 //耗时
Sequence (clock) time:00:00:08.4375000 //总耗时
测试返回省市区表对象3304,以下是用手写的实体集合
===============================================
Request Count: 1//请求数
Bytes Sent: 1,088//发送字节
Bytes Received: 634,171//接收字节
ACTUAL PERFORMANCE
--------------
Requests started at:10:16:07:2500//请求开始
Responses completed at:10:16:09:5625//响应返回
Aggregate Session time:00:00:02:3125//耗时
Sequence (clock) time:00:00:02.3125000//总耗时
===================华丽的分割线========================================
相差了6秒多,而且字节数相差了4倍左右,3304个实体的数据总量一共是600K左右,传600K数据需要8秒?
我把这两个集合序列化到文本一看,一个edmx生成的实体类集合有2.33MB的容量,手写的实体集合只有610K,实际上手写的
实体集合序列化为Soap-XML进行传输的时候那些声明数据的类型的XML节点只占用了10K的大小,而通过edmx生成的
Soap-XML包含了edmx的许多属性,这样就能得出为什么手写的比生成的快了.