MySoft.Data发现系列一:实体的解耦

  自老毛开始发布他的MySoft.Data系列组件,也陆续开始写Mysoft.Data使用系列的文章,我也尝试着写一点自己在研究和使用MySoft.Data过程中的一些心得。

  

  本章介绍Mysoft.Data在作为一个ORM组件应用在系统中时,如何把MySoft.Data生成的实体转换成“干净”的实体,以实现系统和ORM之间的解耦。

  大家都知道,一般ORM组件会有他们自己的特定的实体,例如EF的实体,或者其他ORM组件的实体,要么通过Attribute标记,要么xml文档配置,总而言之就是要把实体的结构跟数据表结构联系起来,MySoft.Data也不例外,大家来看它生成的实体:

代码
  1 /// <summary>
  2     /// 表名:Category 主键列:CategoryID
  3     /// </summary>
  4     [SerializableAttribute()]
  5     public partial class Category : Entity
  6     {
  7 
  8         protected Int32 _CategoryID;
  9 
 10         protected String _Name;
 11 
 12         protected Int32 _UserID;
 13 
 14         public Int32 CategoryID
 15         {
 16             get
 17             {
 18                 return this._CategoryID;
 19             }
 20             set
 21             {
 22                 this.OnPropertyValueChange(_.CategoryID, _CategoryID, value);
 23                 this._CategoryID = value;
 24             }
 25         }
 26 
 27         public String Name
 28         {
 29             get
 30             {
 31                 return this._Name;
 32             }
 33             set
 34             {
 35                 this.OnPropertyValueChange(_.Name, _Name, value);
 36                 this._Name = value;
 37             }
 38         }
 39 
 40         public Int32 UserID
 41         {
 42             get
 43             {
 44                 return this._UserID;
 45             }
 46             set
 47             {
 48                 this.OnPropertyValueChange(_.UserID, _UserID, value);
 49                 this._UserID = value;
 50             }
 51         }
 52 
 53         /// <summary>
 54         /// 获取实体对应的表名
 55         /// </summary>
 56         protected override Table GetTable()
 57         {
 58             return new Table<Category>("Category");
 59         }
 60 
 61         /// <summary>
 62         /// 获取实体中的标识列
 63         /// </summary>
 64         protected override Field GetIdentityField()
 65         {
 66             return _.CategoryID;
 67         }
 68 
 69         /// <summary>
 70         /// 获取实体中的主键列
 71         /// </summary>
 72         protected override Field[] GetPrimaryKeyFields()
 73         {
 74             return new Field[] {
 75                         _.CategoryID};
 76         }
 77 
 78         /// <summary>
 79         /// 获取列信息
 80         /// </summary>
 81         protected override Field[] GetFields()
 82         {
 83             return new Field[] {
 84                         _.CategoryID,
 85                         _.Name,
 86                         _.UserID};
 87         }
 88 
 89         /// <summary>
 90         /// 获取列数据
 91         /// </summary>
 92         protected override object[] GetValues()
 93         {
 94             return new object[] {
 95                         this._CategoryID,
 96                         this._Name,
 97                         this._UserID};
 98         }
 99 
100         /// <summary>
101         /// 给当前实体赋值
102         /// </summary>
103         protected override void SetValues(IRowReader reader)
104         {
105             if ((false == reader.IsDBNull(_.CategoryID)))
106             {
107                 this._CategoryID = reader.GetInt32(_.CategoryID);
108             }
109             if ((false == reader.IsDBNull(_.Name)))
110             {
111                 this._Name = reader.GetString(_.Name);
112             }
113             if ((false == reader.IsDBNull(_.UserID)))
114             {
115                 this._UserID = reader.GetInt32(_.UserID);
116             }
117         }
118 
119         public override int GetHashCode()
120         {
121             return base.GetHashCode();
122         }
123 
124         public override bool Equals(object obj)
125         {
126             if ((obj == null))
127             {
128                 return false;
129             }
130             if ((false == typeof(Category).IsAssignableFrom(obj.GetType())))
131             {
132                 return false;
133             }
134             if ((((object)(this)) == ((object)(obj))))
135             {
136                 return true;
137             }
138             return false;
139         }
140 
141         public class _
142         {
143 
144             /// <summary>
145             /// 表示选择所有列,与*等同
146             /// </summary>
147             public static AllField All = new AllField<Category>();
148 
149             /// <summary>
150             /// 字段名:CategoryID - 数据类型:Int32
151             /// </summary>
152             public static Field CategoryID = new Field<Category>("CategoryID");
153 
154             /// <summary>
155             /// 字段名:Name - 数据类型:String
156             /// </summary>
157             public static Field Name = new Field<Category>("Name");
158 
159             /// <summary>
160             /// 字段名:UserID - 数据类型:Int32
161             /// </summary>
162             public static Field UserID = new Field<Category>("UserID");
163         }
164     }

 我们来看看其实Category实体无非也就那么几个属性

1 public interface Category : IEntity
2     {
3         [PrimaryKey]
4         int CategoryID { get; }
5         string Name { getset; }
6         int UserID { getset; }
7     }

如果使用MySoft.Data的实体,那就意味着你离不开MySoft.Data框架。

而实际项目中我们一定不会这么做(简单的项目就不说了),那么如何如何使用简单的“失血”实体和这个ORM中的实体项目转换呢,其实MySoft.Data里已经提供了灰常简单的方法,我们先来看看MySoft.Data里定义的接口:

代码
 1 /// <summary>
 2     /// 列表转换
 3     /// </summary>
 4     public interface IListConvert<T>
 5     {
 6         /// <summary>
 7         /// 返回另一类型的列表
 8         /// </summary>
 9         /// <typeparam name="TOutput"></typeparam>
10         /// <returns></returns>
11         ISourceList<TOutput> ConvertTo<TOutput>();
12 
13         /// <summary>
14         /// 返回另一类型的列表(输出为接口)
15         /// </summary>
16         /// <typeparam name="TOutput"></typeparam>
17         /// <typeparam name="IOutput"></typeparam>
18         /// <returns></returns>
19         ISourceList<IOutput> ConvertTo<TOutput, IOutput>();
20 
21         /// <summary>
22         /// 将当前类型转成另一种类型
23         /// </summary>
24         /// <typeparam name="TOutput"></typeparam>
25         /// <param name="converter"></param>
26         /// <returns></returns>
27         ISourceList<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter);
28     }

我们再来看看,它的继承关系

代码
 1 /// <summary>
 2     /// 数据源接口
 3     /// </summary>
 4     public interface ISourceList<T> : IListConvert<T>, IArrayList<T>
 5     {
 6         /// <summary>
 7         /// 转换成SourceTable
 8         /// </summary>
 9         /// <returns></returns>
10         ISourceTable ToTable();
11 
12         /// <summary>
13         /// 返回MemoryFrom
14         /// </summary>
15         /// <returns></returns>
16         MemoryFrom<T> ToMemory();
17 
18         /// <summary>
19         /// 添加一个实体
20         /// </summary>
21         /// <param name="item"></param>
22         /// <returns></returns>
23         new ISourceList<T> Add(T item);
24 
25         /// <summary>
26         /// 添加一个实体
27         /// </summary>
28         /// <param name="item"></param>
29         /// <returns></returns>
30         ISourceList<T> AddRange(IEnumerable<T> collection);
31 
32         #region 字典操作
33 
34         /// <summary>
35         /// 返回字典
36         /// </summary>
37         /// <typeparam name="TResult"></typeparam>
38         /// <param name="groupName"></param>
39         /// <returns></returns>
40         IDictionary<TResult, IList<T>> ToGroupList<TResult>(string groupName);
41 
42         /// <summary>
43         /// 返回字典
44         /// </summary>
45         /// <typeparam name="TResult"></typeparam>
46         /// <param name="groupField"></param>
47         /// <returns></returns>
48         IDictionary<TResult, IList<T>> ToGroupList<TResult>(Field groupField);
49 
50         #endregion
51     }

ISourceList<T>继承自IListConvert<T>和IArrayList<T>,IArrayList<T>是啥,IArrayList<T>是一个实现了IList<T>的东东,因此,实现ISourceList<T>,一定会实现IList<T>,我们就可以使用可爱的IList<T>了。

但实际上,MySoft.Data里的SourceList实现了ISourceList,不仅如此,SourceList还(间接)实现了List<T>,大家看它的继承关系

代码
  1 /// <summary>
  2     /// 数组列表
  3     /// </summary>
  4     /// <typeparam name="T"></typeparam>
  5     public class SourceList<T> : ArrayList<T>, ISourceList<T>
  6     {
  7         public SourceList() { }
  8 
  9         /// <summary>
 10         /// 实例化SourceList
 11         /// </summary>
 12         /// <param name="list"></param>
 13         public SourceList(IList<T> list)
 14             : base(list)
 15         { }
 16 
 17         #region IArrayList<T> 成员
 18 
 19         /// <summary>
 20         /// 转换成SourceTable
 21         /// </summary>
 22         /// <returns></returns>
 23         public ISourceTable ToTable()
 24         {
 25             return new SourceTable(this.GetDataTable());
 26         }
 27 
 28         /// <summary>
 29         /// 返回MemoryFrom
 30         /// </summary>
 31         /// <returns></returns>
 32         public MemoryFrom<T> ToMemory()
 33         {
 34             return new MemoryFrom<T>(this.GetDataTable());
 35         }
 36 
 37         /// <summary>
 38         /// 返回另一类型的列表(用于实体的解耦))
 39         /// </summary>
 40         /// <typeparam name="TOutput"></typeparam>
 41         /// <returns></returns>
 42         public ISourceList<TOutput> ConvertTo<TOutput>()
 43         {
 44             return this.ConvertAll<TOutput>(p => DataUtils.ConvertType<T, TOutput>(p));
 45         }
 46 
 47         /// <summary>
 48         /// 将当前类型转成另一种类型
 49         /// </summary>
 50         /// <typeparam name="TOutput"></typeparam>
 51         /// <param name="converter"></param>
 52         /// <returns></returns>
 53         public new ISourceList<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter)
 54         {
 55             IList<TOutput> list = base.ConvertAll<TOutput>(converter);
 56             return new SourceList<TOutput>(list);
 57         }
 58 
 59         /// <summary>
 60         /// 添加一个实体
 61         /// </summary>
 62         /// <param name="item"></param>
 63         /// <returns></returns>
 64         public new ISourceList<T> Add(T item)
 65         {
 66             base.Add(item);
 67             return this;
 68         }
 69 
 70         /// <summary>
 71         /// 添加一个实体
 72         /// </summary>
 73         /// <param name="item"></param>
 74         /// <returns></returns>
 75         public new ISourceList<T> AddRange(IEnumerable<T> collection)
 76         {
 77             base.AddRange(collection);
 78             return this;
 79         }
 80 
 81         /// <summary>
 82         /// 返回另一类型的列表(输入为类、输出为接口,用于实体的解耦)
 83         /// </summary>
 84         /// <typeparam name="TOutput"></typeparam>
 85         /// <typeparam name="IOutput"></typeparam>
 86         /// <returns></returns>
 87         public ISourceList<IOutput> ConvertTo<TOutput, IOutput>()
 88         {
 89             if (!typeof(TOutput).IsClass)
 90             {
 91                 throw new MySoftException("TOutput必须是Class类型!");
 92             }
 93 
 94             if (!typeof(IOutput).IsInterface)
 95             {
 96                 throw new MySoftException("IOutput必须是Interface类型!");
 97             }
 98 
 99             //进行两次转换后返回
100             return ConvertTo<TOutput>().ConvertTo<IOutput>();
101         }
102 
103         #region 字典操作
104 
105         /// <summary>
106         /// 返回字典
107         /// </summary>
108         /// <typeparam name="TResult"></typeparam>
109         /// <param name="groupField"></param>
110         /// <returns></returns>
111         public IDictionary<TResult, IList<T>> ToGroupList<TResult>(Field groupField)
112         {
113             return ToGroupList<TResult>(groupField.PropertyName);
114         }
115 
116         /// <summary>
117         /// 返回字典
118         /// </summary>
119         /// <typeparam name="TResult"></typeparam>
120         /// <param name="groupName"></param>
121         /// <returns></returns>
122         public IDictionary<TResult, IList<T>> ToGroupList<TResult>(string groupName)
123         {
124             IDictionary<TResult, IList<T>> group = new Dictionary<TResult, IList<T>>();
125             if (this.Count == 0return group;
126 
127             foreach (T t in this)
128             {
129                 object obj = DataUtils.GetPropertyValue(t, groupName);
130                 TResult value = DataUtils.ConvertValue<TResult>(obj);
131                 if (!group.ContainsKey(value))
132                 {
133                     group.Add(value, new SourceList<T>());
134                 }
135                 group[value].Add(t);
136             }
137 
138             return group;
139         }
140 
141         #endregion
142 
143         /// <summary>
144         ///  转换成DataTable
145         /// </summary>
146         /// <returns></returns>
147         private DataTable GetDataTable()
148         {
149             #region 对list进行转换
150 
151             DataTable dt = new DataTable();
152             dt.TableName = typeof(T).Name;
153 
154             T obj = DataUtils.CreateInstance<T>();
155             PropertyInfo[] plist = obj.GetType().GetProperties();
156             foreach (PropertyInfo p in plist)
157             {
158                 Type propertyType = p.PropertyType;
159                 if (!CanUseType(propertyType)) continue//shallow only
160 
161                 //nullables must use underlying types
162                 if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
163                     propertyType = Nullable.GetUnderlyingType(propertyType);
164                 //enums also need special treatment
165                 if (propertyType.IsEnum)
166                     propertyType = Enum.GetUnderlyingType(propertyType); //probably Int32
167 
168                 dt.Columns.Add(p.Name, propertyType);
169             }
170 
171             if (this.Count == 0return dt;
172 
173             foreach (T t in this)
174             {
175                 DataRow dtRow = dt.NewRow();
176                 foreach (PropertyInfo p in plist)
177                 {
178                     object value = DataUtils.GetPropertyValue(t, p.Name);
179                     dtRow[p.Name] = value == null ? DBNull.Value : value;
180                 }
181                 dt.Rows.Add(dtRow);
182             }
183 
184             #endregion
185 
186             return dt;
187         }
188 
189         private static bool CanUseType(Type propertyType)
190         {
191             //only strings and value types
192             if (propertyType.IsArray) return false;
193             if (!propertyType.IsValueType && propertyType != typeof(string)) return false;
194             return true;
195         }
196 
197         #endregion
198     }

看来,我们不用担心兼容问题了,它就是List。

说了这么多废话,怎么使用它转成干净的实体呢??

 

项目中,我们可以把实体定义成接口,或者直接实体也行,怎么用,来看看这几个方法,这是今天我在ben的开源blog,xpress看到的

代码
 1  /// <summary>
 2         /// 获取评论列表
 3         /// </summary>
 4         /// <param name="status">状态</param>
 5         /// <param name="pageNumber">页码</param>
 6         /// <param name="pageSize">分页大小</param>
 7         /// <returns></returns>
 8         public IList<IComments> GetList(CommentStatus status, int pageNumber, int pageSize)
 9         {
10             return repository.GetSession().From<Comments>()
11                     .Where(Comments._.CommentStatus == status)
12                     .OrderBy(Comments._.CommentTimeGMT.Desc)
13                     .GetPage(pageSize)
14                     .ToList(pageNumber).ConvertTo<CommentsModel, IComments>();//这里转化了成了SourceList<IComments>,而由于SourceList实现了IList<T>,因此兼容IList<IComments>了
15         }
16 
17 
18 //再来看这几个个扩展方法
19 
20 /// <summary>
21         /// 转换成实体
22         /// </summary>
23         /// <typeparam name="TEntity"></typeparam>
24         /// <param name="entity"></param>
25         /// <returns></returns>
26         public static TEntity ToEntity<TEntity>(this DsJian.Interface.Model.IEntity entity)
27             where TEntity : MySoft.Data.Entity
28         {
29             return new MySoft.Data.SourceList<DsJian.Interface.Model.IEntity>(entity).ConvertTo<TEntity>()[0];
30         }
31 
32         /// <summary>
33         /// 转换成实体
34         /// </summary>
35         /// <typeparam name="TEntity"></typeparam>
36         /// <param name="entity"></param>
37         /// <returns></returns>
38         public static TEntity ToEntity<TEntity>(this MySoft.Data.Entity entity)
39         {
40             return new MySoft.Data.SourceList<MySoft.Data.Entity>(entity).ConvertTo<TEntity>()[0];
41         }
42 
43         /// <summary>
44         /// 转换成接口
45         /// </summary>
46         /// <typeparam name="TEntity"></typeparam>
47         /// <typeparam name="IEntity"></typeparam>
48         /// <param name="entity"></param>
49         /// <returns></returns>
50         public static IEntity ToIEntity<TEntity, IEntity>(this MySoft.Data.Entity entity)
51             where IEntity : DsJian.Interface.Model.IEntity
52         {
53             return new MySoft.Data.SourceList<MySoft.Data.Entity>(entity).ConvertTo<TEntity, IEntity>()[0];
54         }

我不用说,大家也该知道怎么用了。

OK,我是个不怎么会写东西的人,文章中可能有什么胡言乱语的云云,请大家爱护环境,留住你们手中紧攥的臭鸡蛋,谢谢!

 

 

 

 

 

posted on 2010-03-16 17:23  uxspy  阅读(578)  评论(1编辑  收藏  举报

导航