问题描述
如何将json对象数据保存到数据库对应的表中。
分析问题
json数据内容不固定,json数据格式是固定的(name:value),数据库表结构是固定的,在json数据格式 与 数据库表结构之间建立一套对应规则,写一套逻辑解析这套对应规则。
1、json对象对应的数据库表需要确定。
2、json对象的节点对应数据库表的列需要确定。
3、json对象的value类型需要确定下来,才能对value值做相应的操作。
4、数据库表的主键列比较特殊,一般是自增长列,需要确定。
5、数据库记录一般是假删除,有一个删除状态列,需要确定。
6、json对象的value的类型是json时,此列为外键,确定主表,获取主表主键。
7、json对象的value的类型是array是,json此节点的数据为从表的数据,确定从表,对从表操作。
解决问题实例
一、自定义特性
定义了两个特性,EntityAttribute特性用于实体,PropertyAttribute特性用于属性
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Standard.Frame.BEntity { /// <summary> /// 实体特性 /// </summary> [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public class EntityAttribute : Attribute { public EntityAttribute(String entityName, String tableName) { EntityName = entityName; TableName = tableName; } /// <summary> /// 实体名称 /// </summary> public string EntityName { get; set; } /// <summary> /// 表名称 /// </summary> public string TableName { get; set; } } /// <summary> /// 属性特性 /// </summary> [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] public class PropertyAttribute : Attribute { public PropertyAttribute() { } /// <summary> /// json节点名称 /// </summary> public string FieldName { get; set; } /// <summary> /// 列名称 /// </summary> public string ColumnName { get; set; } /// <summary> /// 节点类型 /// </summary> public string NodeType { get; set; } /// <summary> /// 是否是主键 /// </summary> public string IsPK { get; set; } /// <summary> /// 是否删除 /// </summary> public string IsDeletedFlag { get; set; } /// <summary> /// 主实体 /// </summary> public string MainEntity { get; set; } } }
二、在实体、属性上添加特性
这里特性的作用:
1、建立json对象与数据库表的对应关系。
2、建立json节点的name与数据库表列的对应关系。
3、指定json节点value的类型,类型主要有三类:字符串、json对象、数组。
4、标示出主键列。
5、标示出删除标示列。
6、标示出主实体列,类似于关系表的外键关系。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Standard.Frame.Config; namespace Standard.Frame.BEntity { /// <summary> /// 项目信息 /// </summary> [Entity("PlanProject", "XMGL_20")] public class PlanProject:BaseBEntity { /// <summary> /// 项目ID /// </summary> [Property(FieldName = "planProjectID", ColumnName = "XMGL_20_COL_10", NodeType = NodeType.String, IsPK = BooleanType.True)] public string PlanProjectID { get; set; } /// <summary> /// 项目名称 /// </summary> [Property(FieldName = "planProjectName", ColumnName = "XMGL_20_COL_70", NodeType = NodeType.String)] public string PlanProjectName { get; set; } /// <summary> /// 是否已删除 /// </summary> [Property(FieldName = NodeOperation.Operation, ColumnName = "XMGL_20_COL_200", NodeType = NodeType.String, IsDeletedFlag = BooleanType.True)] public string IsDeleted { get; set; } /// <summary> /// 创建时间 /// </summary> [Property(FieldName = "createTime", ColumnName = "XMGL_20_COL_210", NodeType = NodeType.String)] public string CreateTime { get; set; } /// <summary> /// 创建人 /// </summary> [Property(FieldName = "creatorID", ColumnName = "XMGL_20_COL_220", NodeType = NodeType.Json, MainEntity = "User")] public string CreatorID { get; set; } /// <summary> /// 项目组成员 /// </summary> [Property(FieldName = "projectMember", NodeType = NodeType.Array, MainEntity = "ProjectMember")] public string ProjectMember { get; set; } } /// <summary> /// 项目组成员信息 /// </summary> [Entity("ProjectMember", "XMGL_220")] public class ProjectMember : BaseBEntity { /// <summary> /// 人员ID /// </summary> [Property(FieldName = "projectMemberID", ColumnName = "XMGL_220_COL_10", NodeType = NodeType.String, IsPK = BooleanType.True)] public string ProjectMemberID { get; set; } /// <summary> /// 姓名 /// </summary> [Property(FieldName = "projectMemberName", ColumnName = "XMGL_220_COL_20", NodeType = NodeType.String)] public string ProjectMemberName { get; set; } /// <summary> /// 性别 /// </summary> [Property(FieldName = "sex", ColumnName = "XMGL_220_COL_30", NodeType = NodeType.String)] public string Sex { get; set; } /// <summary> /// 备注 /// </summary> [Property(FieldName = "notes", ColumnName = "XMGL_220_COL_110", NodeType = NodeType.String)] public string Notes { get; set; } /// <summary> /// 是否已删除 /// </summary> [Property(FieldName = NodeOperation.Operation, ColumnName = "XMGL_220_COL_200", NodeType = NodeType.String, IsDeletedFlag = BooleanType.True)] public string IsDeleted { get; set; } /// <summary> /// 创建时间 /// </summary> [Property(FieldName = "createTime", ColumnName = "XMGL_220_COL_210", NodeType = NodeType.String)] public string CreateTime { get; set; } /// <summary> /// 创建人 /// </summary> [Property(FieldName = "creatorID", ColumnName = "XMGL_220_COL_220", NodeType = NodeType.Json, MainEntity = "User")] public string CreatorID { get; set; } /// <summary> /// 项目 /// </summary> [Property(FieldName = "planProject", ColumnName = "XMGL_20_COL_10", NodeType = NodeType.Json, MainEntity = "PlanProject")] public string PlanProject { get; set; } } }
三、反射机制,分析实体特性、属性特性,将json对象数据保存到数据库。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; using Standard.Frame.BEntity; using Standard.Frame.Utility; using Standard.Frame.Config; using Standard.Frame.DBAccess; using System.Reflection; using Standard.Frame.Utility; namespace Standard.Frame.BLRuler { public class JsonToTable { public static void Save(object inputJsonObj) { try { SaveJsonObj(inputJsonObj, "PlanProject", null); } catch (Exception e) { LogUtility.Write(DateTime.Now.ToString() + " : " + e.Message); } } /// <summary> /// 保存输入的json对象 /// </summary> /// <param name="inputJsonObj"></param> /// <param name="entityName"></param> private static void SaveJsonObj(object inputJsonObj, string entityName, Tuple<string, object> tupleFk) { Dictionary<string, object> dicReq = CommonFacade.ParseJsonObjToDic(inputJsonObj); Type type = CommonFacade.GetEntityType(entityName); string tableName = CommonFacade.GetTableNameByType(type); System.Reflection.PropertyInfo[] properties = type.GetProperties(); //先保存主表数据(string类型的节点) object recordID = SaveStringNode(dicReq, tableName, properties, tupleFk); //保存从表数据(array类型的节点) SaveArrayNode(dicReq, properties, entityName, recordID); } /// <summary> /// 保存json对象中的字符串节点 /// </summary> /// <param name="dicReq"></param> /// <param name="tableName"></param> /// <param name="properties"></param> /// <param name="tupleFk"></param> /// <returns></returns> private static object SaveStringNode(Dictionary<string, object> dicReq, string tableName, System.Reflection.PropertyInfo[] properties,Tuple<string, object> tupleFk) { PreSqlAccess sqlAccess = new PreSqlAccess(); Dictionary<string, object> dicTable = new Dictionary<string, object>(); Tuple<string, object> tuplePk = ParseStringNode(dicReq, properties, dicTable); if (tupleFk != null) { dicTable.Remove(tupleFk.Item1); dicTable.Add(tupleFk.Item1, tupleFk.Item2); } object recordID = sqlAccess.InsertOrUpdateDataSync(tableName, dicTable, tuplePk);//保存到数据库 return recordID; } /// <summary> /// 保存从表数据(数据类型为array的节点) /// </summary> /// <param name="dicReq"></param> /// <param name="properties"></param> /// <param name="recordID"></param> private static void SaveArrayNode(Dictionary<string, object> dicReq, System.Reflection.PropertyInfo[] properties, string mainEntityName, object recordID) { System.Attribute[] attrs = null; foreach (System.Reflection.PropertyInfo p in properties) { attrs = System.Attribute.GetCustomAttributes(p); foreach (System.Attribute attr in attrs) { if (attr is PropertyAttribute) { PropertyAttribute propertyAttr = (PropertyAttribute)attr; if (dicReq.ContainsKey(propertyAttr.FieldName) && propertyAttr.NodeType == NodeType.Array) { Tuple<string, object> tupleFk = GetTupleFKID(propertyAttr.MainEntity, mainEntityName, recordID); List<object> listObj = CommonFacade.ParseJsonObjToList(dicReq[propertyAttr.FieldName]); listObj.ForEach((inputJsonObj) => { SaveJsonObj(inputJsonObj, propertyAttr.MainEntity, tupleFk); }); } } } } } /// <summary>/// 解析输入json对象中的字符串节点 /// </summary> /// <param name="dicReq"></param> /// <param name="properties"></param> /// <returns></returns> private static Tuple<string, object> ParseStringNode(Dictionary<string, object> dicReq, System.Reflection.PropertyInfo[] properties, Dictionary<string, object> dicTable) { Tuple<string, object> tuplePk = null; System.Attribute[] attrs = null; foreach (System.Reflection.PropertyInfo p in properties) { attrs = System.Attribute.GetCustomAttributes(p); foreach (System.Attribute attr in attrs) { if (attr is PropertyAttribute) { PropertyAttribute propertyAttr = (PropertyAttribute)attr; if (dicReq.ContainsKey(propertyAttr.FieldName)) { if (propertyAttr.IsPK == BooleanType.True) {//记录主键,备用 tuplePk = new Tuple<string, object>(propertyAttr.ColumnName, dicReq[propertyAttr.FieldName]); break; } if (propertyAttr.IsDeletedFlag == BooleanType.True) {//"是否删除" 这个标示列需要特殊处理 if (dicReq.ContainsKey(NodeOperation.Operation) && Convert.ToString(dicReq[propertyAttr.FieldName]) == NodeOperationType.Deleted) dicTable.Add(propertyAttr.ColumnName, 1); break; } if (propertyAttr.NodeType == NodeType.String) dicTable.Add(propertyAttr.ColumnName, dicReq[propertyAttr.FieldName]); if (propertyAttr.NodeType == NodeType.Json) dicTable.Add(propertyAttr.ColumnName,CommonFacade.GetPKID(dicReq[propertyAttr.FieldName], propertyAttr.MainEntity)); } } } } return tuplePk; } /// <summary>/// 将主表ID匹配到从表对应的外键 /// </summary> /// <param name="inputJsonObj"></param> /// <param name="entityName"></param> /// <param name="mainEntityName"></param> /// <param name="recordID"></param> /// <returns></returns> private static Tuple<string, object> GetTupleFKID(string entityName, string mainEntityName, object recordID) { Tuple<string, object> tupleFK = null; Type type = CommonFacade.GetEntityType(entityName); System.Reflection.PropertyInfo[] properties = type.GetProperties(); System.Attribute[] attrs = null; foreach (System.Reflection.PropertyInfo p in properties) { attrs = System.Attribute.GetCustomAttributes(p); foreach (System.Attribute attr in attrs) { if (attr is PropertyAttribute) { PropertyAttribute propertyAttr = (PropertyAttribute)attr; if (propertyAttr.NodeType == NodeType.Json && propertyAttr.MainEntity == mainEntityName) { tupleFK = new Tuple<string, object>(propertyAttr.ColumnName,recordID); goto outer; } } } } outer: return tupleFK; } } }
四、操作数据库
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Data; using System.Data.SqlClient; using Standard.Frame.Config; namespace Standard.Frame.DBAccess { public class PreSqlAccess { /// <summary>/// 同步插入记录 /// </summary> /// <param name="tablename"></param> /// <param name="dicTable"></param> /// <returns></returns> private object InsertRecordSync(string tablename, Dictionary<string, object> dicTable) { StringBuilder columns = new StringBuilder(); StringBuilder datas = new StringBuilder(); List<IDataParameter> parameters = new List<IDataParameter>(); foreach (var item in dicTable) { columns.Append(item.Key).Append(","); datas.Append("@" + item.Key).Append(","); parameters.Add(new SqlParameter("@" + item.Key, item.Value)); } StringBuilder sqlCommand = new StringBuilder(); sqlCommand.Append(" insert into "); sqlCommand.Append(tablename).Append(" ( ").Append(columns.ToString().Trim(new char[] { ‘,‘ })).Append(" ) "); sqlCommand.Append(" values ( ").Append(datas.ToString().Trim(new char[] { ‘,‘ })).Append(" ) "); SqlAccess sqlAccess = new SqlAccess(); return sqlAccess.InsertRecordSync(tablename, sqlCommand.ToString(), CommandType.Text, parameters.ToArray(), null); } /// <summary>/// 同步更新记录 /// </summary> /// <param name="tablename"></param> /// <param name="dicTable"></param> /// <param name="tuplePk"></param> /// <returns></returns> private object UpdateRecordSync(string tablename, Dictionary<string, object> dicTable, Tuple<string, object> tuplePk) { StringBuilder columnValues = new StringBuilder(); List<IDataParameter> parameters = new List<IDataParameter>(); foreach (var item in dicTable) { columnValues.Append(item.Key).Append("=").Append("@" + item.Key).Append(","); parameters.Add(new SqlParameter("@" + item.Key, item.Value)); } StringBuilder sqlCommand = new StringBuilder(); sqlCommand.Append(" update ").Append(tablename); sqlCommand.Append(" set "); sqlCommand.Append(columnValues.ToString().Trim(new char[] { ‘,‘ })); sqlCommand.Append(" where ").Append(tuplePk.Item1).Append("=").Append(tuplePk.Item2); SqlAccess sqlAccess = new SqlAccess(); return sqlAccess.ExecuteNonQuerySync(sqlCommand.ToString(), CommandType.Text, parameters.ToArray(), null); } /// <summary> /// 插入或者更新记录 返回记录ID /// </summary> /// <param name="tablename"></param> /// <param name="dicTable"></param> /// <param name="tuplePk"></param> /// <returns></returns> public object InsertOrUpdateDataSync(string tablename, Dictionary<string, object> dicTable, Tuple<string, object> tuplePk = null) { object recordID = default(object); if (dicTable.ContainsKey(NodeOperation.Operation)) { switch (Convert.ToString(dicTable[NodeOperation.Operation])) { case NodeOperationType.Added: dicTable.Remove(NodeOperation.Operation); recordID=InsertRecordSync(tablename, dicTable); break; case NodeOperationType.Changed: case NodeOperationType.Deleted: dicTable.Remove(NodeOperation.Operation); recordID = tuplePk.Item2; UpdateRecordSync(tablename, dicTable, tuplePk); break; default: ; break; } } return recordID; } } }
时间: 2024-12-14 11:59:04