在Farseer.Net 中 ORM的核心在命名空间:FS.ORM 。
目前只有4个类文件。其实这4个文件只要是用来做数据库与实体模型之间的映射关系及缓存。至于SQL生成、不同数据库的驱动支持等 在另外的命名空间:FS.Core 中。
对于ORM来说,我们在转换成数据库操作前,是先让Farseer.Net能“读懂”实体与数据库之间的关系,才能做出对应的SQL生成操作。在本框架中,实际都是最终生成SQL。交由ADO.NET来完成执行数据库操作的。
Mapping.cs :映射的核心文件,都是通过该类,来完成对实体与数据库之间的映射过程。
ModelCache.cs :映射缓存,致使我们不需要对实体进行重复的反射操作。将会在第一次映射后缓存起来。
DBAttribute.cs :顾名思义,是数据库的特性。比如前面我们看到在实体类名称的特征:[DB(Name="xxx表名称",DbIndex = 1)]
ModelAttribute.cs :这个是属性字段的映射,包括字段的名称、中文名称、必填、长度、自增列等。
这个对象将会对实体类的表信息、字段信息(多个)进行全面解析。
1 /// <summary> 2 /// ORM 映射关系 3 /// </summary> 4 public class Mapping 5 { 6 /// <summary> 7 /// 获取所有属性 8 /// </summary> 9 public readonly Dictionary<PropertyInfo, ModelAttribute> ModelList; 10 11 /// <summary> 12 /// 关系映射 13 /// </summary> 14 /// <param name="type">实体类Type</param> 15 internal Mapping(Type type) 16 17 /// <summary> 18 /// 类属性 19 /// </summary> 20 public DBAttribute ClassInfo { get; set; } 21 22 /// <summary> 23 /// 自增ID 24 /// </summary> 25 public string IndexName { get; set; } 26 27 /// <summary> 28 /// 类型 29 /// </summary> 30 public Type Type { get; set; } 31 32 /// <summary> 33 /// 通过实体类型,返回Mapping 34 /// </summary> 35 public static implicit operator Mapping(Type type) 36 37 /// <summary> 38 /// 获取当前属性(通过使用的propertyName) 39 /// </summary> 40 /// <param name="propertyName">属性名称</param> 41 public KeyValuePair<PropertyInfo, ModelAttribute> GetModelInfo(string propertyName = "") 42 43 /// <summary> 44 /// 获取标注的名称 45 /// </summary> 46 /// <param name="propertyInfo">属性变量</param> 47 /// <returns></returns> 48 public string GetUserName(PropertyInfo propertyInfo) 49 }
Mapping的构造函数传入的是实体类的Type。然后对这个类进行 《类特性》、《属性特性》的转化。同时因为这里涉及到数据库类型及访问方式了,所以Db.Config如果不存在,则会创建这份配置文件出来。
同时加入对数据验证的错误提示:
1 // 字符串长度判断 2 if (modelAtt.StringLength != null && modelAtt.StringLength.ErrorMessage.IsNullOrEmpty()) 3 { 4 if (modelAtt.StringLength.MinimumLength > 0 && modelAtt.StringLength.MaximumLength > 0) 5 { 6 modelAtt.StringLength.ErrorMessage = string.Format("{0},长度范围必需为:{1} - {2} 个字符之间!", modelAtt.Display.Name, modelAtt.StringLength.MinimumLength, modelAtt.StringLength.MaximumLength); 7 } 8 else if (modelAtt.StringLength.MaximumLength > 0) 9 { 10 modelAtt.StringLength.ErrorMessage = string.Format("{0},长度不能大于{1}个字符!", modelAtt.Display.Name, modelAtt.StringLength.MaximumLength); 11 } 12 else 13 { 14 modelAtt.StringLength.ErrorMessage = string.Format("{0},长度不能小于{1}个字符!", modelAtt.Display.Name, modelAtt.StringLength.MinimumLength); 15 } 16 } 17 18 // 值的长度 19 if (modelAtt.Range != null && modelAtt.Range.ErrorMessage.IsNullOrEmpty()) 20 { 21 if (modelAtt.Range.Minimum.ConvertType(0m) > 0 && modelAtt.Range.Maximum.ConvertType(0m) > 0) 22 { 23 modelAtt.Range.ErrorMessage = string.Format("{0},的值范围必需为:{1} - {2} 之间!", modelAtt.Display.Name, modelAtt.Range.Minimum.ConvertType(0m), modelAtt.Range.Maximum.ConvertType(0m)); 24 } 25 else if (modelAtt.Range.Maximum.ConvertType(0m) > 0) 26 { 27 modelAtt.Range.ErrorMessage = string.Format("{0},的值不能大于{1}!", modelAtt.Display.Name, modelAtt.Range.Maximum.ConvertType(0m)); 28 } 29 else 30 { 31 modelAtt.Range.ErrorMessage = string.Format("{0},的值不能小于{1}!", modelAtt.Display.Name, modelAtt.Range.Minimum.ConvertType(0m)); 32 } 33 }
通过ModelList,我们可以获取该类的所有字段信息。这对我们在一些项目执行的过程中需要动态的获取类属性的信息是很有需要的。
GetModelInfo,通过传入数据库字段名称,找到映射的类属性。
GetFieldName,通过传入类属性,找到映射的数据库字段信息。
1 namespace FS.ORM 2 { 3 /// <summary> 4 /// 缓存数据库和实体类的映射关系 5 /// </summary> 6 public static class ModelCache 7 { 8 /// <summary> 9 /// 缓存所有实体类 10 /// </summary> 11 private static readonly Dictionary<Type, Mapping> ModelList = new Dictionary<Type, Mapping>(); 12 13 private static readonly object LockObject = new object(); 14 15 /// <summary> 16 /// 返回实体类映射的信息 17 /// </summary> 18 /// <param name="type">实体类Type</param> 19 public static Mapping GetInfo(Type type) 20 { 21 if (!ModelList.ContainsKey(type)) 22 { 23 lock (LockObject) 24 { 25 if (!ModelList.ContainsKey(type)) 26 { 27 ModelList.Add(type, new Mapping(type)); 28 } 29 } 30 } 31 32 return ModelList[type]; 33 } 34 35 /// <summary> 36 /// 清除缓存 37 /// </summary> 38 public static void ClearCache() 39 { 40 ModelList.Clear(); 41 } 42 } 43 }
ModelCache对象就是将Mapping进行缓存的操作。通过GetInfo方法,进行缓存并返回Mapping对象。
因此大家如果需要Mapping对象时,必须通过ModelCache.GetInfo的静态方法进行获取。否则直接操作Mapping对象,将会引发性能问题。
存储与数据库的类型、访问方式,及表名称。
1 /// <summary> 2 /// 实体类的属性标记 3 /// </summary> 4 [AttributeUsage(AttributeTargets.Class)] 5 public sealed class DBAttribute : Attribute 6 { 7 /// <summary> 8 /// 表名 9 /// </summary> 10 public string Name { get; set; } 11 12 /// <summary> 13 /// 设置数据库连接配置(Dbconfig)的索引项 14 /// </summary> 15 public int DbIndex { get; set; } 16 17 /// <summary> 18 /// 设置数据库连接字符串 19 /// </summary> 20 public string ConnStr { get; set; } 21 22 /// <summary> 23 /// 设置数据库类型 24 /// </summary> 25 public DataBaseType DataType { get; set; } 26 27 /// <summary> 28 /// 设置数据库版本 29 /// </summary> 30 public string DataVer { get; set; } 31 32 /// <summary> 33 /// 设置数据库执行T-SQL时间,单位秒默认是30秒 34 /// </summary> 35 public int CommandTimeout { get; set; }
这里代码比较少,我就不在贴上来了,大家可以到框架中查看。大部份的特性,我们还是利用LINQ TO SQL的。可以减少大家的学习成本。
主要是针对字段的必填、数据长度、数字值类型的范围、或者正则(可自定义加入如邮件格式、手机格式的验证)。
另外需要说明的是,默认所有字段都是映射到数据库字段的。如果有一些额外的字段不想加入到字段中。
可以在字段的特性申明:[NotJoinAttribute(true)],表明该类属性不对数据库的字段进行映射。
QQ群:116228666 (Farseer.net开源框架交流) 请注明:Farseer.Net
Farseer.Net是一款ORM框架 + 常用工具 + 扩展集合。
Farseer 意为:先知、预言家 通常在某些场合时,提供计谋、策略。也希望该框架能给大家提供最大化的便捷。
ORM:其英文全称是:Object(对象) Relational(关系) Mapping(映射)
Farseer.Net的目标是:快速上手、快速开发、简单方便。
1 new User { ID = 1, Name = "张三" }.Insert()