公司目前用xml存储数据,不过之前是面向过程的,我觉得麻烦,于是抽象了一个数据存取操作的类,在一定程度上避免了重复造轮子..
此方法可以处理用于使用xml存储小量数据的项目,比如配置文件等
此方法对xml的操作需要将整个文件load到内存中,并且节点转Model时用了反射,这些是此方法比较明显的缺点,不过对于公司目前的开发效率提升还是比较明显的帮助的
/// <summary> /// 基类 /// 直接继承此类时表示不用文件单独存储的TEntity类型 只支持ModelToElement和PraseModel非文件操作辅助方法 /// 如主类中存储子类,此时子类的操作类继承此类以辅助主类的存取 /// </summary> public class Infrastructure<TEntity> where TEntity : class, new() { //主键列表 public List<string> PrimaryKeys; //字段列表 随用随取 public List<PropertyInfo> EntityPropertys; //节点名称 即tentity名称 public readonly string ModelName; public Infrastructure() { EntityPropertys = typeof (TEntity).GetProperties().ToList(); PrimaryKeys = GetPrimaryKeys(); ModelName = typeof (TEntity).Name; } /// <summary> /// 把xml元素转成model /// 自定义枚举类不被识别 以名称字符串对比 /// </summary> /// <param name="element"></param> public TEntity PraseModel(XElement element) { TEntity result = new TEntity(); if (element == null) { return null; } try { EntityPropertys.ForEach(ppt => { var node = element.Element(ppt.Name); if (node == null) { return; } if (ppt.PropertyType == typeof (string)) { ppt.SetValue(result, node.Value, null); } else if (ppt.PropertyType == typeof (bool)) { ppt.SetValue(result, bool.Parse(node.Value), null); } else if (ppt.PropertyType == typeof (decimal)) { ppt.SetValue(result, decimal.Parse(node.Value), null); } else if (ppt.PropertyType == typeof (ushort)) { ppt.SetValue(result, ushort.Parse(node.Value), null); } else if (ppt.PropertyType == typeof (byte)) { ppt.SetValue(result, byte.Parse(node.Value), null); } else if (ppt.PropertyType == typeof (uint)) { ppt.SetValue(result, uint.Parse(node.Value), null); } else if (ppt.PropertyType.Name.Equals(typeof (SystemTypeEnum).Name)) { ppt.SetValue(result, Enum.Parse(typeof (SystemTypeEnum), node.Value), null); } else if (ppt.PropertyType.Name.Equals(typeof (SexTypeEnum).Name)) { ppt.SetValue(result, Enum.Parse(typeof (SexTypeEnum), node.Value.ToUpper()), null); } else if (ppt.PropertyType == typeof (double)) { ppt.SetValue(result, double.Parse(node.Value), null); } else if (ppt.PropertyType.Name.Equals(typeof (AnimalFamilyEnum).Name)) { ppt.SetValue(result, Enum.Parse(typeof (AnimalFamilyEnum), node.Value), null); } else if (ppt.PropertyType == typeof (DateTime)) { ppt.SetValue(result, DateTime.Parse(node.Value), null); } }); return result; } catch (Exception e) { OtherOperation.WriteErrorIntoRecord(e.Message); return null; } } /// <summary> /// model转元素 /// </summary> /// <param name="model"></param> /// <returns></returns> public XElement ModelToElement(TEntity model) { var modelDict = ModelToDict(model); return DictToXelement(modelDict); } /// <summary> /// 取主键列表 /// </summary> private List<string> GetPrimaryKeys() { PrimaryKeys = new List<string>(); EntityPropertys.ForEach(ppt => { var attrs = ppt.GetCustomAttributes(true); if (!attrs.Any()) { return; } foreach (object attr in attrs) { if ((attr as KeyAttribute) != null) { //标识了Key特性的字段 PrimaryKeys.Add(ppt.Name); } } }); return PrimaryKeys; } /// <summary> /// model转字典 /// </summary> /// <param name="model"></param> public Dictionary<string, object> ModelToDict(TEntity model) { var dict = new Dictionary<string, object>(); EntityPropertys.ForEach(ppt => { dict[ppt.Name] = ppt.GetValue(model, null); }); return dict; } /// <summary> /// 字典转元素 /// </summary> /// <param name="dict"></param> public XElement DictToXelement(Dictionary<string, object> dict) { var result = new XElement(ModelName); foreach (var key in dict.Keys) { if (PrimaryKeys.Contains(key)) { //添加主键特性 result.SetAttributeValue(key, dict[key]); } var element = new XElement(key, dict[key]); result.Add(element); } return result; } }
/// <summary> /// 有单独xml文件存储的TEntity操作类需要继承该类 /// </summary> public class Repository<TEntity> : Infrastructure<TEntity> where TEntity : class, new() { //数据存储的文档xml对象 public XElement XElement; //存储文件路径 ([相对路径/]文件名.ric) private readonly string _location; public Repository(string location) { if (!string.IsNullOrWhiteSpace(_location)) { throw new Exception("FilePath Cann‘t Be Empty!"); } _location = location; if (!File.Exists(location)) { BuildXmlFile(); } try { XElement = XElement.Load(location); } catch (Exception e) { throw new Exception(e.Message); } } /// <summary> /// 新增 有主键model新增主键相同的实例 不写入文件 判定写入成功 /// </summary> /// <param name="entity">model实例</param> public virtual bool Insert(TEntity entity) { var elementDict = ModelToDict(entity); if (PrimaryKeys.Any() && HasModel(elementDict)) { return true; } XElement.Add(DictToXelement(elementDict)); return Save(); } /// <summary> /// 新增多个 有主键model重复新增主键相同的实例 不写入文件 判定写入成功 /// </summary> /// <param name="entitys">model集合</param> public virtual bool Insert(IEnumerable<TEntity> entitys) { foreach (TEntity entity in entitys) { var elementDict = ModelToDict(entity); if (PrimaryKeys.Any() && HasModel(elementDict)) { continue; } XElement.Add(DictToXelement(elementDict)); } return Save(); } /// <summary> /// 单主键删除 /// </summary> /// <param name="id">主键值</param> public virtual bool Delete(object id) { var dict = new Dictionary<string, object>(); if (PrimaryKeys.Any() && PrimaryKeys.Count == 1) { dict[PrimaryKeys[0]] = id; } else { return false; } var element = GetXElememt(dict); try { element.Remove(); } catch (Exception e) { OtherOperation.WriteErrorIntoRecord(e.Message); return false; } return Save(); } /// <summary> /// 删除 /// </summary> /// <param name="entity">model实例</param> public virtual bool Delete(TEntity entity) { XElement element = ModelToElement(entity); try { element.Remove(); } catch (Exception e) { OtherOperation.WriteErrorIntoRecord(e.Message); return false; } return Save(); } /// <summary> /// 删除多个 /// </summary> /// <param name="entitys"></param> public virtual bool Delete(IEnumerable<TEntity> entitys) { try { foreach (TEntity entity in entitys) { var element = ModelToElement(entity); element.Remove(); } } catch (Exception e) { OtherOperation.WriteErrorIntoRecord(e.Message); return false; } return Save(); } /// <summary> /// 修改 需model有主键定位需要修改的实例 /// </summary> /// <param name="entity">model实例</param> public virtual bool Update(TEntity entity) { if (!PrimaryKeys.Any()) { OtherOperation.WriteErrorIntoRecord("Delete failure! No primary key to locate element!"); return false; } var dict = ModelToDict(entity); //用主键序列去文件中找到需要替换的元素 var elementInFile = GetXElememt(dict); if (elementInFile == null) { //本地没有被替换的元素则改更新为新增 return Insert(entity); } try { elementInFile.ReplaceWith(ModelToElement(entity)); } catch (Exception e) { OtherOperation.WriteErrorIntoRecord(e.Message); return false; } return Save(); } /// <summary> /// 取一个 /// </summary> /// <param name="id">主键值</param> /// <returns></returns> public virtual TEntity GetModel(object id) { var dict = new Dictionary<string, object>(); if (PrimaryKeys.Any() && PrimaryKeys.Count == 1) { dict[PrimaryKeys[0]] = id; } else { return null; } try { var element = GetXElememt(dict); return PraseModel(element); } catch (Exception e) { OtherOperation.WriteErrorIntoRecord(e.Message); return null; } } /// <summary> /// 取第一个 没有则返回null /// </summary> /// <returns></returns> public virtual TEntity GetFirstOrDefault() { try { return PraseModel(XElement.FirstNode as XElement); } catch { return null; } } /// <summary> /// 取全部 /// </summary> public virtual List<TEntity> GetAllDatas() { var nodes = XElement.Nodes(); var result = new List<TEntity>(); foreach (XNode node in nodes) { var entity = PraseModel(node as XElement); if (entity != null) { result.Add(entity); } } return result; } /// <summary> /// 保存修改 在此类内调用方法修改后直接保存 /// 覆写以上方法需主动调用此方法保存 /// </summary> public virtual bool Save() { try { XElement.Save(_location); } catch (Exception e) { OtherOperation.WriteErrorIntoRecord(e.Message); return false; } return true; } /// <summary> /// 建立xml文档 写架构 (TEntity.Name).ric 架构可通过Model的字段特性申明具体属性 /// </summary> public void BuildXmlFile() { if (File.Exists(_location)) { return; } var table = new DataTable(ModelName); EntityPropertys.ForEach(ppt => { var dc = new DataColumn(ppt.Name, ppt.PropertyType) { AllowDBNull = !PrimaryKeys.Contains(ppt.Name) }; //AllowDBNull属性可以用特性申明 if (ppt.PropertyType == typeof (string)) { dc.MaxLength = 50; } table.Columns.Add(dc); }); table.WriteXml(_location, XmlWriteMode.WriteSchema); } /// <summary> /// 查找文件中是否有此元素 /// </summary> /// <param name="dict"></param> public bool HasModel(Dictionary<string, object> dict) { return GetXElememt(dict) != null; } /// <summary> /// 根据字典取元素 有主键就按主键取 没主键就节点取 Default = null /// </summary> /// <param name="dict"></param> public XElement GetXElememt(Dictionary<string, object> dict) { XElement result; if (PrimaryKeys.Any() && PrimaryKeys.All(pk=>dict.Keys.Contains(pk))) { result = XElement.Elements().AsQueryable().FirstOrDefault(node => PrimaryKeys.All(d => node.Attribute(d) != null && node.Attribute(d).Value == (string) dict[d])); } else { result = XElement.Elements().AsQueryable().FirstOrDefault(node => dict.All(d => node.Element(d.Key) != null && node.Element(d.Key).Value == (string) d.Value)); } return result; }