95992828九五至尊2

代码生成插件,网站动态属性的三个架构882828九五至尊手机版

二月 22nd, 2019  |  882828九五至尊手机版

睡不着,讲讲方今做的三个类型的架构的一有的吗,那是3个门类管理种类,匡助动态属性,也等于说贰个素材
– 例如“项目”、“职责”就是质感,资料的属性
– 例如“名称”、“时间”都是可以在系统运维时动态增删改的。

    YbSoftwareFactory
各类插件的基本功类库中又新增了五个方便易用的效果:动态属性增加与键值生成器,本章将各自介绍那三个要命有益的零部件。

本文就讲一讲在.NET和SQL Server里已毕动态属性的法门,纵然演示代码都以C#,但本身深信不疑可以很不难的移植到Java中。

一 、动态属性扩张 

第②定义多少个名词:

   
在骨子里的费用进度中,你肯定会碰着数据库字段不够用的动静,目前扩充三个字段有时是很辛劳的一件事。例如须要修改
SQL 语句、视图、存储进程等等,固然你使用的是 OCRUISERM
组件,也亟需充实和配备映射,每便修改形成后还需反复开展测试,分外的不便利,如若软件已经为客户布署好了的话,嘿嘿,不用说,肯定更让你感冒;而客户一时半刻要添加新的字段的情况却是非平常见的。其余,某个对象实际不合乎放置一张主表中,即便那是
1:1
的关联,因为直接助长到一张表只怕会设有一定的品质难题,例如图片、文件等新闻,有个别时候查询
N
多记录重临大量消息一般不是有理和英明的做法,在字段数量很多的景观下,对于有个别不根本的字段新闻保存到其余表中寻常是可以升级查询质量的。

资料 – 是对此系统最后用户来说其要有限支撑的数量,例如“项目”、“义务”音信等。

   
本章介绍的动态属性伸张效率主要就是化解此类题材,能够灵活、方便的恢宏属性。

属性 – 即资料的贰个上边的数码,只怕称作字段,在C#代码里应该就是二个Property。

   
注:动态属性扩张组件主要面向正在开发中的审批流组件而陈设的,其目标是为巅峰用户提供灵活、方便、易用的性质自定义的法力。动态属性增加组件已购并到数量字典组件、社团机关管理组件中。 

元数据 – 是表达属性的艺术,有时自身也会把它称作元属性。

    本组件具有如下鲜明特点:

质量和元数据的关系吧,能够参照Excel的贯彻来了解,好比说咱俩在多个单元格里输入了一个数码,实际上大家是输入了一个字符串,假如是“1”,当大家设置Excel使用“数字”格式呈现时,那用户在单元格里实际看来的是“1.0”,当大家设置Excel使用“日期”格式突显时,这用户在单元格里见到的可能就是“一九零四-1-1”。这里,字符串“1”就是性质,而元数据实际上就类似Excel里的格式。

  1. 活动完毕动态属性值的加载和封存,通过键/值对的办法贯彻动态扩大属性的数据库保存和加载,卓殊的方便。假若您想玩得更高级点,可以平昔从界面绑定1个动态属性,然后保留到数据库并能重新加载并绑定到界面上,这一历程无需你像一些软件接近的对所谓的元数据开展管理和安插,分外灵活。
  2. 能自行完结品质类型的更换,因为字段的属性值是通过键值对的法门保留到内定的数据库表中,由此需求把数据库中保存的文本型的属性值自动转换到钦命的类型(如日期、整数、二进制音信)等。本文介绍的动态属性扩充成效可成功此类型的变换。
  3. 协助对象的种类化,那对于利用
    WCF、Web 瑟维斯、Web API
    等类似的技巧举行长途数据交互是很有必不可少的。 

对于资料来说,它只保留一本品质列表,而属性有三个外键指向定义其格式的元数据,上边是材质、属性和元数据的C#定义:

    至于具体的完成原理,毫无疑问是利用了 .NET 4.0 的 Dynamic
本性,如下是骨干基类的贯彻代码:

 

882828九五至尊手机版 1882828九五至尊手机版 2

资料

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Dynamic;
  5 using System.Reflection;
  6 
  7 namespace Yb.Data.Provider
  8 {
  9     [Serializable]
 10     public class ExtensionObject: DynamicObject, IDynamicMetaObjectProvider
 11     {
 12         object _instance;
 13 
 14         Type _instanceType;
 15         PropertyInfo[] _cacheInstancePropertyInfos;
 16         IEnumerable<PropertyInfo> _instancePropertyInfos
 17         {
 18             get
 19             {
 20                 if (_cacheInstancePropertyInfos == null && _instance != null)                
 21                     _cacheInstancePropertyInfos = _instance.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
 22                 return _cacheInstancePropertyInfos;                
 23             }
 24         }
 25 
 26         public ExtensionObject() 
 27         {
 28             Initialize(this);            
 29         }
 30 
 31         /// <remarks>
 32         /// You can pass in null here if you don’t want to 
 33         /// check native properties and only check the Dictionary!
 34         /// </remarks>
 35         /// <param name=”instance”></param>
 36         public ExtensionObject(object instance)
 37         {
 38             Initialize(instance);
 39         }
 40 
 41 
 42         protected virtual void Initialize(object instance)
 43         {
 44             _instance = instance;
 45             if (instance != null)
 46                 _instanceType = instance.GetType();           
 47         }
 48 
 49        /// <param name=”binder”></param>
 50        /// <param name=”result”></param>
 51        /// <returns></returns>
 52         public override bool TryGetMember(GetMemberBinder binder, out object result)
 53         {
 54             result = null;
 55 
 56             // first check the Properties collection for member
 57             if (Properties.Keys.Contains(binder.Name))
 58             {
 59                 result = Properties[binder.Name];
 60                 return true;
 61             }
 62 
 63 
 64             // Next check for Public properties via Reflection
 65             if (_instance != null)
 66             {
 67                 try
 68                 {
 69                     return GetProperty(_instance, binder.Name, out result);                    
 70                 }
 71                 catch (Exception)
 72                 { }
 73             }
 74 
 75             // failed to retrieve a property
 76             return false;
 77         }
 78 
 79         /// <param name=”binder”></param>
 80         /// <param name=”value”></param>
 81         /// <returns></returns>
 82         public override bool TrySetMember(SetMemberBinder binder, object value)
 83         {
 84 
 85             // first check to see if there’s a native property to set
 86             if (_instance != null)
 87             {
 88                 try
 89                 {
 90                     bool result = SetProperty(_instance, binder.Name, value);
 91                     if (result)
 92                         return true;
 93                 }
 94                 catch { }
 95             }
 96             
 97             // no match – set or add to dictionary
 98             Properties[binder.Name] = value;
 99             return true;
100         }
101 
102         /// <param name=”binder”></param>
103         /// <param name=”args”></param>
104         /// <param name=”result”></param>
105         /// <returns></returns>
106         public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
107         {
108             if (_instance != null)
109             {
110                 try
111                 {
112                     // check instance passed in for methods to invoke
113                     if (InvokeMethod(_instance, binder.Name, args, out result))
114                         return true;                    
115                 }
116                 catch (Exception)
117                 { }
118             }
119 
120             result = null;
121             return false;
122         }
123         
124         /// <param name=”instance”></param>
125         /// <param name=”name”></param>
126         /// <param name=”result”></param>
127         /// <returns></returns>
128         protected bool GetProperty(object instance, string name, out object result)
129         {
130             if (instance == null)
131                 instance = this;
132 
133             var miArray = _instanceType.GetMember(name, BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.Instance);
134             if (miArray != null && miArray.Length > 0)
135             {
136                 var mi = miArray[0];
137                 if (mi.MemberType == MemberTypes.Property)
138                 {
139                     result = ((PropertyInfo)mi).GetValue(instance,null);
140                     return true;
141                 }
142             }
143 
144             result = null;
145             return false;                
146         }
147 
148         /// <param name=”instance”></param>
149         /// <param name=”name”></param>
150         /// <param name=”value”></param>
151         /// <returns></returns>
152         protected bool SetProperty(object instance, string name, object value)
153         {
154             if (instance == null)
155                 instance = this;
156 
157             var miArray = _instanceType.GetMember(name, BindingFlags.Public | BindingFlags.SetProperty | BindingFlags.Instance);
158             if (miArray != null && miArray.Length > 0)
159             {
160                 var mi = miArray[0];
161                 if (mi.MemberType == MemberTypes.Property)
162                 {
163                     ((PropertyInfo)mi).SetValue(_instance, value, null);
164                     return true;
165                 }
166             }
167             return false;                
168         }
169 
170         /// <param name=”instance”></param>
171         /// <param name=”name”></param>
172         /// <param name=”args”></param>
173         /// <param name=”result”></param>
174         /// <returns></returns>
175         protected bool InvokeMethod(object instance, string name, object[] args, out object result)
176         {
177             if (instance == null)
178                 instance = this;
179 
180             // Look at the instanceType
181             var miArray = _instanceType.GetMember(name,
182                                     BindingFlags.InvokeMethod |
183                                     BindingFlags.Public | BindingFlags.Instance);
184 
185             if (miArray != null && miArray.Length > 0)
186             {
187                 var mi = miArray[0] as MethodInfo;
188                 result = mi.Invoke(_instance, args);
189                 return true;
190             }
191 
192             result = null;
193             return false;
194         }
195 
196         public object this[string key]
197         {
198             get
199             {
200                 try
201                 {
202                     // try to get from properties collection first
203                     return Properties[key];
204                 }
205                 catch (KeyNotFoundException ex)
206                 {
207                     // try reflection on instanceType
208                     object result = null;
209                     if (GetProperty(_instance, key, out result))
210                         return result;
211 
212                     // nope doesn’t exist
213                     throw;
214                 }
215             }
216             set
217             {
218                 if (Properties.ContainsKey(key))
219                 {
220                     Properties[key] = value;
221                     return;
222                 }
223 
224                 // check instance for existance of type first
225                 var miArray = _instanceType.GetMember(key, BindingFlags.Public | BindingFlags.GetProperty);
226                 if (miArray != null && miArray.Length > 0)
227                     SetProperty(_instance, key, value);
228                 else
229                     Properties[key] = value;
230             }
231         }
232 
233         /// <param name=”includeInstanceProperties”></param>
234         /// <returns></returns>
235         public IEnumerable<KeyValuePair<string,object>> GetProperties(bool includeInstanceProperties = false)
236         {
237             if (includeInstanceProperties && _instance != null)
238             {
239                 foreach (var prop in this._instancePropertyInfos)
240                     yield return new KeyValuePair<string, object>(prop.Name, prop.GetValue(_instance, null));
241             }
242 
243             foreach (var key in this.Properties.Keys)
244                yield return new KeyValuePair<string, object>(key, this.Properties[key]);
245 
246         }
247 
248         /// <param name=”item”></param>
249         /// <param name=”includeInstanceProperties”></param>
250         /// <returns></returns>
251         public bool Contains(KeyValuePair<string, object> item, bool includeInstanceProperties = false)
252         {
253             bool res = Properties.ContainsKey(item.Key);
254             if (res)
255                 return true;
256 
257             if (includeInstanceProperties && _instance != null)
258             {
259                 foreach (var prop in this._instancePropertyInfos)
260                 {
261                     if (prop.Name == item.Key)
262                         return true;
263                 }
264             }
265 
266             return false;
267         }
268         /// <param name=”key”></param>
269         /// <returns></returns>
270         public bool Contains(string key, bool includeInstanceProperties = false)
271         {
272             bool res = Properties.ContainsKey(key);
273             if (res)
274                 return true;
275 
276             if (includeInstanceProperties && _instance != null)
277             {
278                 foreach (var prop in this._instancePropertyInfos)
279                 {
280                     if (prop.Name == key)
281                         return true;
282                 }
283             }
284 
285             return false;
286         }
287         
288     }
289 }

 

ExtensionObject

  1  public class GenericDynamicPropertiesEntity : IDynamicPropertiesTable, ISupportDefaultProperties
  2     {
  3         public GenericDynamicPropertiesEntity()
  4         {
  5             Properties = new List<Property>();
  6             this.FillDefaultProperties();
  7         }
  8 
  9         public string Get(string name)
 10         {
 11             var property = this.Property(name, false);
 12             if (property != null)
 13             {
 14                 return property.Value;
 15             }
 16             else
 17             {
 18                 return null;
 19             }
 20         }
 21 
 22         public Property Get(MetaProperty meta)
 23         {
 24             var property = this.Property(meta.Title, false);
 25             if (property != null)
 26             {
 27                 return this.Property(meta.Title, false);
 28             }
 29             else
 30             {
 31                 return null;
 32             }
 33         }
 34         public void Set(string name, string value)
 35         {
 36             var property = this.Property(name, true);
 37             if (property.Meta.Valid(value))
 38                 property.Value = value;
 39             else
 40                 throw new InvalidValueException(string.Format(“字段\”{0}\”的值\”{1}\”无效,字段\”{0}\”的品种是\”{2}\”, 期望值的格式是\”{3}\””,
 41                     name, value, property.Meta.Type, property.Meta.ExpectedFormat));
 42         }
 43 
 44         public void Set(string name, double value)
 45         {
 46             var property = this.Property(name, true);
 47             if (property.Meta.Valid(value))
 48                 property.Value = value.ToString();
 49             else
 50                 throw new InvalidValueException(string.Format(“字段\”{0}\”的值\”{1}\”无效,字段\”{0}\”的体系是\”{2}\”, 期望值的格式是\”{3}\””,
 51                     name, value, property.Meta.Type, property.Meta.ExpectedFormat));
 52         }
 53 
 54         public List<Property> Properties { get; private set; }
 55 
 56         [DataMember]
 57         public Guid Id { get; set; }
 58 
 59         public static T New<T>() where T : GenericDynamicPropertiesEntity, new()
 60         {
 61             return new T()
 62             {
 63                 Id = Guid.NewGuid()
 64             };
 65         }
 66 
 67         protected void SetClassValue<T>(string propertyName, T member, T value)
 68         {
 69             member = value;
 70             Set(propertyName, value != null ? value.ToJson() : null);
 71         }
 72 
 73         protected void SetNullableDateTime<T>(string propertyName, T? member, T? value) where T : struct
 74         {
 75             member = value;
 76             Set(propertyName, value.HasValue ? value.Value.ToString() : null);
 77         }
 78 
 79         protected void SetDateTime(string propertyName, DateTime member, DateTime value)
 80         {
 81             member = value;
 82             Set(propertyName, value.ToString());
 83         }
 84 
 85         protected void SetSingle(string propertyName, float member, float value)
 86         {
 87             member = value;
 88             Set(propertyName, value);
 89         }
 90 
 91         protected void SetPrimeValue<T>(string propertyName, T member, T value) where T : struct
 92         {
 93             member = value;
 94             Set(propertyName, value.ToString());
 95         }
 96 
 97         protected DateTime? GetNullableDateTime(string propertyName, DateTime? date)
 98         {
 99             if (!date.HasValue)
100             {
101                 var value = Get(propertyName);
102                 if (value != null)
103                 {
104                     date = DateTime.Parse(value);
105                 }
106             }
107 
108             return date;
109         }
110 
111         protected float GetSingle(string propertyName, float member)
112         {
113             if (float.IsNaN(member))
114             {
115                 var property = this.Property(propertyName, false);
116                 if (property != null)
117                 {
118                     member = Single.Parse(property.Value);
119                 }
120             }
121 
122             return member;
123         }
124 
125         protected DateTime GetDateTime(string propertyName, DateTime member)
126         {
127             if (member == DateTime.MinValue)
128             {
129                 var value = Get(propertyName);
130                 if (value != null)
131                 {
132                     member = DateTime.Parse(value);
133                     return member;
134                 }
135                 else
136                 {
137                     throw new PropertyNotFoundException(string.Format(“在Id为\”{0}\”的对象里找不到名为\”{1}\”的属性!”, Id, propertyName));
138                 }
139             }
140             else
141             {
142                 return member;
143             }
144         }
145 
146         public DateTime? ClosedDate
147         {
148             get;
149             set;
150         }
151 
152         public DateTime OpenDate
153         {
154             get;
155             set;
156         }
157 
158         public DateTime LastModified
159         {
160             get;
161             set;
162         }
163 
164         public string Creator
165         {
166             get;
167             set;
168         }
169 
170         public string LastModifiedBy
171         {
172             get;
173             set;
174         }
175     }

   
具体的行使,仅需两次三番该对象即可。为了更好的认证具体用法,请查看如下已测试通过的单元测试代码:

属性

882828九五至尊手机版 3882828九五至尊手机版 4

 

  1         [Serializable]
  2         public class User : ExtensionObject
  3         {
  4             public Guid UserId { get; set; }
  5             public string Email { get; set; }
  6             public string Password { get; set; }
  7             public string Name { get; set; }
  8             public bool Active { get; set; }
  9             public DateTime? ExpiresOn { get; set; }
 10 
 11             public User()
 12                 : base()
 13             { }
 14 
 15             // only required if you want to mix in seperate instance
 16             public User(object instance)
 17                 : base(instance)
 18             {
 19             }
 20         }
 21 
 22         /// <summary>
 23         /// ExtensionData 的测试
 24         ///</summary>
 25         [TestMethod()]
 26         public void ExtensionObjectTest()
 27         {
 28             //清空数据库存储的属性值,方便开展测试
 29             ExtensionDataApi.ClearExtensionDataOfApplication();
 30 
 31             var user = new User();
 32             // 设置已有总体性
 33             dynamic duser = user;
 34             user.UserId = Guid.NewGuid();
 35             duser.Email = “19892257@qq.com”;
 36             user.Password = “YbSofteareFactory”;
 37 
 38             // 设置动态属性
 39             duser.FriendUserName = “YB”;
 40             duser.CreatedDate = DateTime.Now;
 41             duser.TodayNewsCount = 1;
 42             duser.Age = 27.5;
 43             duser.LastUpdateId = (Guid?)null;
 44             duser.LastUpdatedDate=null;
 45 
 46             // 动态属性值保存
 47             ExtensionDataApi.SaveExtensionObject(user.UserId,user);
 48             
 49             // 从数据库中加载属性值
 50             var obj = user.LoadExtensionData(user.UserId);
 51             
 52             // 测试是还是不是加载正确
 53             Assert.AreEqual(obj.FriendUserName, “YB”);
 54             Assert.IsNotNull(obj.CreatedDate);
 55             Assert.AreEqual(obj.TodayNewsCount, 1);
 56             Assert.AreEqual(obj.Age, 27.5);
 57             Assert.IsNull(obj.LastUpdateId);
 58             Assert.IsNull(obj.LastUpdatedDate);
 59 
 60             var items = ExtensionDataApi.FindExtensionDataBy(user.UserId.ToString(), user);
 61             //测试保存的动态属性数
 62             Assert.IsTrue(items.Count() == 6);
 63 
 64             // 修改动态属性值
 65             duser.Age = 28;
 66             // 新增动态属性
 67             duser.Tag = null;
 68             duser.NewProperty = 12;
 69             //使用增加方法开展封存动态属性值至数据库
 70             user.SaveExtensionData(user.UserId);
 71             
 72             items = ExtensionDataApi.FindExtensionDataBy(user.UserId.ToString(), user);
 73             //判断保存的性质数据是不是正确
 74             Assert.IsTrue(items.Count() == 8);
 75 
 76             //使用扩张方法动态从数据库中加载属性
 77             obj = user.LoadExtensionData(user.UserId);
 78 
 79             Assert.AreEqual(obj.Tag, null);
 80             Assert.AreEqual(obj.NewProperty, 12);
 81 
 82             duser.ComplexObject = user;
 83 
 84             //设置新值
 85             duser.Tag = true;
 86             ExtensionDataApi.SaveExtensionObject(user.UserId, user);
 87             obj = ExtensionDataApi.LoadExtensionObject(user.UserId, user);
 88             // 验证加载的属性新值是或不是科学
 89             Assert.IsTrue(obj.Tag);
 90 
 91             //重返对象数组的习性字典方法测试
 92             var dic = ExtensionDataApi.FindExtensionDataDictionaryBy(new string[]{user.UserId.ToString()}, user.GetType().FullName);
 93             Assert.IsTrue(dic.Count>0);
 94 
 95             //byte[] 测试,对可惠及存储文件、图片等内容
 96             duser.Image = new byte[] {2, 255, 241, 236, 16, 19, 128, 32, 90};
 97             ExtensionDataApi.SaveExtensionObject(user.UserId, user);
 98             obj = ExtensionDataApi.LoadExtensionObject(user.UserId, user);
 99             Assert.AreEqual(obj.Image.Length, 9);
100             Assert.AreEqual(obj.Image[8], 90);
101 
102             //Json 种类化测试,对 Web Api 等尤其主要
103             string json = JsonConvert.SerializeObject(duser, Formatting.Indented, new JsonSerializerSettings
104             {
105                 TypeNameHandling = TypeNameHandling.All,
106                 TypeNameAssemblyFormat = FormatterAssemblyStyle.Full
107             });
108             Assert.IsNotNull(json);
109             json = JsonConvert.SerializeObject(user);
110             Assert.IsNotNull(json);
111         }

 1     /// <summary>
 2     /// 资料的质量
 3     /// </summary>
 4     public class Property : ITable
 5     {
 6         /// <summary>
 7         /// 获取和装置资料的值
 8         /// </summary>
 9         /// <remarks>
10         /// 对于一般品种,例如float等门类直接就保留其ToString的回到结果
11         /// 对于复杂类型,则保留其json格式的靶子
12         /// </remarks>
13         // TODO: 第1版 – 须要考虑国际化景况下,属性有三个值的情状!
14         public string Value { get; set; }
15         
16         /// <summary>
17         /// 获取和安装属性的Id
18         /// </summary>
19         public Guid Id { get; set; }
20 
21         public MetaProperty Meta { get; set; }
22 
23         /// <summary>
24         /// 获取和安装该属性对应的元数据Id
25         /// </summary>
26         public Guid MetaId { get; set; }
27 
28         /// <summary>
29         /// 该属性对应的资料的号子
30         /// </summary>
31         public Guid EntityId { get; set; }
32 
33         /// <summary>
34         /// 获取和设置该属性所属的资料
35         /// </summary>
36         public GenericDynamicPropertiesEntity Entity { get; set; }
37 }

ExtensionObjectTest

元数据

贰 、键值生成器

 

   
键值的变迁看似简单,其实达成起来却并不易于,因为这中间有并发性、生功用率等等方面的考虑。同时,对键值的军事管制也是尤其紧要的,试想想,不一致地点的七个客户端同时生成了一致的键值是怎么结果呢。

  1 public class MetaProperty : INamedTable, ISecret
  2     {
  3         public Guid Id { get; set; }
  4 
  5         public string BelongsToMaterial { get; set; }
  6 
  7         public String Title { get; set; }
  8 
  9         public string Type { get; set; }
 10 
 11         public string DefaultValue { get; private set; }
 12 
 13         /// <summary>
 14         /// 获取和设置属性的权能
 15         /// </summary>
 16         public int Permission { get; set; }
 17 
 18         public virtual string ExpectedFormat { get { return string.Empty; } }
 19 
 20         public virtual bool Valid(string value)
 21         {
 22             return true;
 23         }
 24 
 25         public virtual bool Valid(double value)
 26         {
 27             return true;
 28         }
 29 
 30         public static MetaProperty NewString(string name)
 31         {
 32             return new MetaProperty()
 33             {
 34                 Id = Guid.NewGuid(),
 35                 Title = name,
 36                 Type = Default.MetaProperty.Type.String,
 37                 Permission = Default.Permission.Mask
 38             };
 39         }
 40 
 41         public static MetaProperty NewNumber(string name, double defaultValue = 0.0)
 42         {
 43             return new MetaProperty()
 44             {
 45                 Id = Guid.NewGuid(),
 46                 Title = name,
 47                 Type = Default.MetaProperty.Type.Number,
 48                 Permission = Default.Permission.Mask,
 49                 DefaultValue = defaultValue.ToString()
 50             };
 51         }
 52 
 53         public static MetaProperty NewAddress(string name)
 54         {
 55             return new MetaProperty()
 56             {
 57                 Id = Guid.NewGuid(),
 58                 Title = name,
 59                 Type = Default.MetaProperty.Type.Address,
 60                 Permission = Default.Permission.Mask
 61             };
 62         }
 63 
 64         public static MetaProperty NewRelationship(string name)
 65         {
 66             return new MetaProperty()
 67             {
 68                 Id = Guid.NewGuid(),
 69                 Title = name,
 70                 Type = Default.MetaProperty.Type.Relationship,
 71                 Permission = Default.Permission.Mask
 72             };
 73         }
 74 
 75         public static MetaProperty NewDateTime(string name)
 76         {
 77             return new MetaProperty()
 78             {
 79                 Id = Guid.NewGuid(),
 80                 Title = name,
 81                 Type = Default.MetaProperty.Type.DateTime,
 82                 Permission = Default.Permission.Mask
 83             };
 84         }
 85 
 86         public static MetaProperty NewDate(string name)
 87         {
 88             return new MetaProperty()
 89             {
 90                 Id = Guid.NewGuid(),
 91                 Title = name,
 92                 Type = Default.MetaProperty.Type.Date,
 93                 Permission = Default.Permission.Mask
 94             };
 95         }
 96 
 97         public static MetaProperty NewTime(string name)
 98         {
 99             return new MetaProperty()
100             {
101                 Id = Guid.NewGuid(),
102                 Title = name,
103                 Type = Default.MetaProperty.Type.Time,
104                 Permission = Default.Permission.Mask
105             };
106         }
107 
108         public static MetaProperty NewUser(string name)
109         {
110             return new MetaProperty()
111             {
112                 Id = Guid.NewGuid(),
113                 Title = name,
114                 Type = Default.MetaProperty.Type.User,
115                 Permission = Default.Permission.Mask
116             };
117         }
118 
119         public static MetaProperty NewUrl(string name)
120         {
121             return new UrlMetaProperty()
122             {
123                 Id = Guid.NewGuid(),
124                 Title = name,
125                 Type = Default.MetaProperty.Type.Url,
126                 Permission = Default.Permission.Mask
127             };
128         }
129 
130         public static MetaProperty NewTag(string name)
131         {
132             return new MetaProperty()
133             {
134                 Id = Guid.NewGuid(),
135                 Title = name,
136                 Type = Default.MetaProperty.Type.Tag,
137                 Permission = Default.Permission.Mask
138             };
139         }
140     }
141 
142     public class MetaProperties : List<MetaProperty>
143     {
144         public MetaProperty Find(string name)
145         {
146             return this.SingleOrDefault(p => String.Compare(p.Title, name) == 0);
147         }
148 }

    本章要介绍的键值生成器组件格外灵活和高速,它富有如下万分实用的作用:

 

  1. 支撑绝领先二分之一情景下钦赐格式的键值生成,例如可内定前缀、后缀、客户端应用程序编号(多客户端下相当管用)、日期(例如yyyy、yyyyMM、yyyyMMdd、yyyyMMddHH等)以及流水号长度。
  2. 支撑批量生成键值,三遍可以转移内定数量的键值组。
  3. 在满意一定性能的前提下,可有效缓解广大的面世意况,有效防患键值争论。

保养资料时,使用类似上边的代码就足以给资料创制无限多的天性,可以事先、事后给属性关联元数据,以便定义编辑和呈现格局(里面用到部分Ioc和Mock):

   对于具体的施用方式,同样依旧来探望已经过测试的一部分单元测试代码:

 1      [TestMethod]
 2         public void 验证客户资料的动态属性的可行性()
 3         {
 4             var rep = new MemoryContext();
 5             MemoryMetaSet metas = new MemoryMetaSet();
 6             metas.Add(typeof(Customer), MetaProperty.NewString(“姓名”));
 7             metas.Add(typeof(Customer), MetaProperty.NewNumber(“年龄”));
 8             metas.Add(typeof(Customer), MetaProperty.NewAddress(“地址”));
 9             metas.Add(typeof(Customer), MetaProperty.NewRelationship(“同事”));
10             rep.MetaSet = metas;
11 
12             var builder = new ContainerBuilder();
13             var mocks = new Mockery();
14             var user = mocks.NewMock<IUser>();
15             Expect.AtLeastOnce.On(user).GetProperty(“Email”).Will(Return.Value(DEFAULT_USER_EMAIL));
16 
17             builder.RegisterInstance(user).As<IUser>();
18             builder.RegisterInstance(rep).As<IContext>();
19             var back = IocHelper.Container;
20             try
21             {
22                 IocHelper.Container = builder.Build();
23 
24                 var customer = Customer.New<Customer>();
25                 customer.Set(“姓名”, “XXX”);
26                 customer.Set(“年龄”, 28);
27                 customer.Set(“地址”, “ZZZZZZZZZZZZZZZZZZZZZZ”);
28 
29                 var colleague = Customer.New<Customer>();
30                 colleague.Set(“姓名”, “YYY”);
31 
32                 // 对于有个别复杂一点的目的,我们可以用json对象
33                 customer.Set(“同事”, Relationship.Colleague(customer, colleague).ToString());
34 
35                 Assert.AreEqual(“XXX”, customer.Get(“姓名”));
36             }
37             finally
38             {
39                 IocHelper.Container = back;
40             }
41         }

882828九五至尊手机版 5882828九五至尊手机版 6

 

  1         /// <summary>
  2         ///GetNextID 的测试
  3         ///</summary>
  4         [TestMethod()]
  5         public void GetNextIDTest()
  6         {
  7             IdGeneratorApi.ClearAllIdGenerator();
  8 
  9             var user = new User();
 10 
 11             //生成类似 U-01-201108-001格式的ID,%A表示输出客户端编号,%D代表输出日期时间
 12             var idGen = new IdGenerator()
 13                 {
 14                     Type = typeof (User).FullName,
 15                     DateFormat = “yyyyMM”,
 16                     GenFormat = “U-%A-%D-“,
 17                     Id = Guid.NewGuid(),
 18                     StartValue = 1,
 19                     NextValue = 1,
 20                     ValueLength = 3
 21                 };
 22             //API基本方法测试
 23             IdGeneratorApi.SaveOrUpdateIdGenerator(idGen);
 24             var item = IdGeneratorApi.GetIdGeneratorBy(idGen.Id);
 25             Assert.IsNotNull(item);
 26             item = IdGeneratorApi.GetIdGeneratorBy(user);
 27             Assert.IsNotNull(item);
 28             item = IdGeneratorApi.GetIdGeneratorBy(“not exist’s record”);
 29             Assert.IsNull(item);
 30             //API基本措施测试
 31             Assert.IsTrue(IdGeneratorApi.IdGeneratorExists(user));
 32             Assert.IsFalse(IdGeneratorApi.IdGeneratorExists(“dkakd_test_a”));
 33 
 34             //生成ID号
 35             var str = IdGeneratorApi.GetNextID(user);
 36             Assert.AreEqual(“U-02-201308-001”, str);
 37             str = IdGeneratorApi.GetNextID(user);
 38             Assert.AreEqual(“U-02-201308-002”, str);
 39 
 40             idGen = IdGeneratorApi.GetIdGeneratorBy(idGen.Id);
 41             //无需生成日期,当前转变的ID号类似于U-02–003
 42             idGen.DateFormat = string.Empty;
 43 
 44             IdGeneratorApi.SaveOrUpdateIdGenerator(idGen);
 45             idGen = IdGeneratorApi.GetIdGeneratorBy(idGen.Id);
 46 
 47             //生成下一ID号
 48             str = IdGeneratorApi.GetNextID(user);
 49             Assert.AreEqual(“U-02–003”, str);
 50             str = IdGeneratorApi.GetNextID(user);
 51             Assert.AreEqual(“U-02–004”, str);
 52 
 53             idGen = IdGeneratorApi.GetIdGeneratorBy(idGen.Id);
 54             // 如下代码修改生成的ID号类似于U-0005-
 55             idGen.DateFormat = “yyyyMM”;
 56             //未设置%D,将不再输出日期
 57             idGen.GenFormat = “U-%v-“;
 58             //修改生成编号的尺寸为4
 59             idGen.ValueLength = 4; 
 60             IdGeneratorApi.SaveOrUpdateIdGenerator(idGen);
 61 
 62             str = IdGeneratorApi.GetNextID(user);
 63             Assert.AreEqual(“U-0005-“, str);
 64             str = IdGeneratorApi.GetNextID(user);
 65             Assert.AreEqual(“U-0006-“, str);
 66 
 67             //API基本格局测试
 68             IdGeneratorApi.DeleteIdGenerator(idGen);
 69             item = IdGeneratorApi.GetIdGeneratorBy(idGen.Id);
 70             Assert.IsNull(item);
 71             item = IdGeneratorApi.GetIdGeneratorBy(user);
 72             Assert.IsNull(item);
 73 
 74             IdGeneratorApi.ClearAllIdGeneratorOfApplication();
 75         }
 76 
 77         /// <summary>
 78         ///GetNextGroupID 的测试,批量生产ID号
 79         ///</summary>
 80         [TestMethod()]
 81         public void GetNextGroupIDTest()
 82         {
 83             IdGeneratorApi.ClearAllIdGeneratorOfApplication();
 84 
 85             var user = new User();
 86 
 87             var idGen = new IdGenerator()
 88             {
 89                 Type = typeof(User).FullName,
 90                 DateFormat = “yyyyMM”,
 91                 GenFormat = “U-%a-%D-%v”,
 92                 Id = Guid.NewGuid(),
 93                 StartValue = 1,
 94                 NextValue = 1,
 95                 ValueLength = 3
882828九五至尊手机版, 96             };
 97 
 98             IdGeneratorApi.SaveOrUpdateIdGenerator(idGen);
 99 
100             //批量生成1个ID号
101             var str = IdGeneratorApi.GetNextGroupID(user,3);
102             Assert.IsTrue(str.Length==3);
103             Assert.IsTrue(str[0]==”U-02-201308-001″);
104             Assert.IsTrue(str[1]==”U-02-201308-002″);
105             Assert.IsTrue(str[2]==”U-02-201308-003″);
106 
107             idGen = IdGeneratorApi.GetIdGeneratorBy(idGen.Id);
108             // 如下修改将转移类似于T0004的ID,将忽略日期和客户端编号
109             idGen.GenFormat = “T%v”;
110             idGen.ValueLength = 4;
111             IdGeneratorApi.SaveOrUpdateIdGenerator(idGen);
112 
113             str = IdGeneratorApi.GetNextGroupID(user,2);
114             Assert.IsTrue(str.Length==2);
115             Assert.IsTrue(str[0]==”T0004″);
116             Assert.IsTrue(str[1]==”T0005″);
117 
118             idGen = IdGeneratorApi.GetIdGeneratorBy(idGen.Id);
119             //修改生成的ID格式
120             idGen.DateFormat = “yyyy”;
121             //生成类似于01-0010/二零一三的ID号,%a为客户端编号,%v为流水号,%d将出口日期时间,此处为年度
122             idGen.GenFormat = “%a-%v/%d”;
123             //指明流水号长度为4,类似于0001
124             idGen.ValueLength = 4;
125             IdGeneratorApi.SaveOrUpdateIdGenerator(idGen);
126 
127             str = IdGeneratorApi.GetNextGroupID(user,2);
128             Assert.IsTrue(str.Length==2);
129             Assert.IsTrue(str[0]==”02-0001/2013″);
130             Assert.IsTrue(str[1]==”02-0002/2013″);
131 
132             IdGeneratorApi.ClearAllIdGenerator();
133         }
134 
135         public class User
136         {
137             public string Id { get; set; }
138             public string UserName { get; set; }
139         }

因为动态属性事先不了然其格式,为了落实搜索作用,无法在编写程序的时候拼接查询用的SQL语句,由此小编抽象了一层,定义了2个小的查询语法,写了1个小小的的编译器将查询语句转化成SQL语句,达成了对动态属性的查询功效,请看下边的测试用例:

IdGeneratorTest

 

 
 如今的支付主导将日益向审批流的支付连接,以后的审批流组件将由表单设计器、流程设计器和审批流底层组件三大一些组成,具有灵活、简单、易用的风味,如下是流程设计器的预览界面:

 1         [TestMethod]
 2         public void 测试不难的尺度构成查询()
 3         {
 4             using (var context = IocHelper.Container.Resolve<IContext>())
 5             {
 6                 var customer = Customer.New<Customer>();
 7                 customer.Set(“姓名”, “测试简单的口径构成查询”);
 8                 customer.Set(“年龄”, 28);
 9                 customer.Set(“地址”, “东京市浦东新区”);
10                 context.Customers.Add(customer);
11                 context.SaveChanges();
12 
13                 var result = context.Customers.Query(“(AND (姓名=’测试不难的尺度构成查询’)” +
14                                                      ”     (年龄 介于 1 到 30)” +
15                                                      “)”);
16                 Assert.IsTrue(result.Count() > 0);
17                 var actual = result.First();
18                 Assert.AreEqual(“测试简单的口径构成查询”, actual.Get(“姓名”));
19                 Assert.AreEqual(“28”, actual.Get(“年龄”));
20             }
21         }

 882828九五至尊手机版 7

 

上面测试用例里的查询语句:

(AND (姓名=’测试不难的条件构成查询’) (年龄 介于 1 到 30) )

经过Query函数的编译之后,会转化成上边的两段SQL语句:

SELECT e.*, p.* FROM  Properties AS p INNELAND JOIN  GenericDynamicPropertiesEntities AS e ON p.EntityId = e.Id INNE途乐 JOIN  MetaSet AS m ON p.MetaId = m.Id  WHERE  ((CASE  WHEN m.Type = ‘日期时间型’ AND (CONVE酷威T(datetime, p.Value) = N’测试不难的准绳构成查询’) AND (m.Title = N’姓名’) THEN 1  WHEN m.Type = ‘字符串’ AND (p.Value = N’测试简单的条件构成查询’) AND (m.Title = N’姓名’) THEN 1  ELSE 0 END = 1))

 

SELECT e.*, p.* FROM  Properties AS p INNESportage JOIN  GenericDynamicPropertiesEntities AS e ON p.EntityId = e.Id INNECR-V JOIN  MetaSet AS m ON p.MetaId = m.Id  WHERE  ((CASE  WHEN m.Type = ‘数字型’ AND (CONVE锐界T(int, p.Value) BETWEEN 1 AND 30) AND (m.Title = N’年龄’) THEN 1  WHEN m.Type = ‘日期时间型’ AND (CONVE奥德赛T(datetime, p.Value) BETWEEN N’1′ AND N’30’) AND (m.Title = N’年龄’) THEN 1  ELSE 0 END = 1))

 

然后分别执行查询并在业务层将求解查询结果的混合,可能是可以直接生成一条SQL语句交给数据库处理成最精简的结果再再次回到的,不过因为开发时间、以及目标客户的关系,暂且并未花精力做那一个优化。

理所当然上边的查询语句写起来还比较复杂,由此小编做了三个界面方便用户编辑查询条件,其它对资料属性的编制、元数据珍贵等情节,前边再写文章说,蚊子太多了…… 

 

相关文章

Your Comments

近期评论

    功能


    网站地图xml地图