C#反射在模型与数据库赋值的时候的应用
C#反射在模型与数据库赋值的时候的应用
在这段时间的工作当中,公司给我安排了一个对接Ebay接口的任务,任务中出现了一个问题,就是Ebay的上传模型是一种复杂模型,里面模型一层嵌套一层,在C#转换的时候比较好处理,但是在把下载的数据存入数据库,或者是把数据库的数据序列化成上传模型就会有些问题。
我一开始的时候想到的是我可以直接把Ebay模型转换成Json字符串,然后放到数据库中。这个有优势也有缺点。
优点:
- 模型序列化反序列化方便
缺点
- 存储空间占用大
- 检索数据麻烦
在用了这个一段时间之后,我在想有没有更好的方式,来序列化数据,后来我想了一种新的方式来存储,模型就是一颗树,同一级的名字不一样,比方说 在下图中属性的值表示方法就是
dispalyName | Name | Value |
---|---|---|
属性1 | .属性1 | 123 |
列表1 | .属性2.列表[0] | 123 |
子主题1 | .属性3.子主题1 |
这样存储的话
好处:
- 可以直接检索某个节点的值
- 这个比上面的方法节省点空间
缺点:
- 实现起来麻烦
- 自定义规则,如果有字典类型的话,有点难以处理
以上是我对这个问题的思考
我现在实现了,数据类型转模型的赋值,下面是代码,模型转数据的还是比较简单的,顺着思路反写就可以了
public class ModelHelper
{
static Regex regex = new Regex(@"\.([a-zA-Z_\d]+)(\[(\d)\])?");
public static T InitModel<T>(T rootModel, IEnumerable<KV> kVs)
where T : new()
{
if (rootModel == null || kVs == null)
{
return rootModel;
}
foreach (var kv in kVs.OrderBy(a => a.Key))
{
if (!regex.IsMatch(kv.Key))
{
continue;
}
//抓取所有符合格式的模型节点
Queue<LevelModel> levelModels = new Queue<LevelModel>();
var matches = regex.Matches(kv.Key);
foreach (Match match in matches)
{
var levelModel = new LevelModel()
{
Name = match.Groups[1].Value,//这个是节点名
};
if (!string.IsNullOrWhiteSpace(match.Groups[3]?.Value))
{
levelModel.Index = Convert.ToInt32(match.Groups[3]?.Value);//这个是节点索引
}
levelModels.Enqueue(levelModel);
}
UpdateData(rootModel.GetType(), rootModel, levelModels, kv.Value);
}
return rootModel;
}
public static object UpdateData(Type type, object data, Queue<LevelModel> levelModels, string value)
{
var levelModel = levelModels.Dequeue();//取出队列中的一个对象
//var type= typeof(T);
var prop = type.GetProperties().SingleOrDefault(a => a.Name.Equals(levelModel.Name));
if (prop == null)//判断对象下面的属性有没有这个名字的,如果没有的话 就不用管了
{
return data;
}
try
{
if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(List<>))//如果是泛型
{
levelModel.Index = levelModel.Index ?? 0;
var listData = prop.GetValue(data);
var listType = prop.PropertyType;
listData = InitList(listData, listType, levelModel.Index.Value);
var getMethod = listType.GetMethod("get_Item");
var setMethod = listType.GetMethod("set_Item");
var childType = listType.GetGenericArguments()[0];
var childData = getMethod.Invoke(listData, new object[] { levelModel.Index.Value });
object val = null;
if (levelModels.Count == 0)//没有下面的数值了,在这个属性里面是可以填写对象了
{
val = GetValue(childType, value);
//childData = val;
}
else//如果下面还有层级的话,需要往下找
{
var propData = childData ?? Activator.CreateInstance(childType);
val = UpdateData(prop.PropertyType, propData, levelModels, value);
//prop.SetValue(data, propData);
}
try
{
setMethod.Invoke(listData, new object[] { levelModel.Index.Value, val });
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
prop.SetValue(data, listData);
}
else
{
if (levelModels.Count == 0)//没有下面的数值了,在这个属性里面是可以填写对象了
{
var val = GetValue(prop.PropertyType, value);
prop.SetValue(data, val);
return data;
}
else//如果下面还有层级的话,需要往下找
{
var propData = prop.GetValue(data) ?? Activator.CreateInstance(prop.PropertyType);
propData = UpdateData(prop.PropertyType, propData, levelModels, value);
prop.SetValue(data, propData);
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
return data;
}
/// <summary>
/// 初始化List对象
/// </summary>
/// <param name="obj">对象</param>
/// <param name="type">List类型</param>
/// <param name="num">最终的下标</param>
/// <returns></returns>
public static object InitList(object obj, Type type, int num)
{
if (type.GetGenericTypeDefinition() == typeof(List<>))
{
obj = obj ?? Activator.CreateInstance(type);//如果对象为空,创建之
var countProp = type.GetProperties()
.SingleOrDefault(a => a.Name.Equals("Count"));
var count = (int)countProp.GetValue(obj);//获取List对象的长度
var addMethod = type.GetMethod("Add");//获取List中的添加方法
for (int i = count; i < num + 1; i++)
{
var argType = type.GetGenericArguments()[0];
addMethod?.Invoke(obj, new[] { argType == typeof(string)?"":Activator.CreateInstance(argType) });
}
}
return obj;
}
public static object GetValue(Type tp, string value)
{
try
{
if (tp.IsEnum)
{
if (!int.TryParse(value, out int val))
{
return val;
}
else
{
foreach (var enumValue in tp.GetEnumValues())
{
if (enumValue.ToString().Equals(value))
{
return enumValue;
}
}
}
}else if (tp == typeof(string))
{
return value;
}
else
{
var TryParse = tp.GetMethod("TryParse", BindingFlags.Public | BindingFlags.Static, Type.DefaultBinder,
new Type[] { typeof(string), tp.MakeByRefType() },
new ParameterModifier[] { new ParameterModifier(2) });
var parameters = new object[] { value, Activator.CreateInstance(tp) };
bool success = (bool)TryParse.Invoke(null, parameters);
if (success)
{
return parameters[1];
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
return Activator.CreateInstance(tp);
}
private void MyLogger(string message)
{
}
}
public class KV
{
public string Key { get; set; }
public string Value { get; set; }
}
public class LevelModel
{
/// <summary>
/// 名字
/// </summary>
public string Name { get; set; }
/// <summary>
/// 下标
/// </summary>
public int? Index { get; set; }
}
C#感觉是最漂亮的