.net 8 实现单表sql query 自动ORM

前言:

在我们日常开发中,EF或者EfCore通过导航属性实现的自动ORM已经很方便了,其主要围绕实体为中心的ORM,在复杂场景下可能还是通过sql执行方式比较方便,但是有时候我们需要返回的实体和表结构并不相似,所以基于该场景,我们尝试实现一个基础的单表ORM.

原理: 

1. 通过DbCommand执行sql拿到返回结果DataTable.

2.通过反射自动将实体属性名和sql query result的列名匹配,赋值.

代码实现:

咱们通过给DataTable写一个泛型扩展方法来方便我们后续使用。

1.efcore中封装执行sql的方法.

public async Task<DataTable> ExecuteSqlWithAdo(string sql,List<Tuple<string,string>> parameters)
    {
        var dataTable = new DataTable();
        try
        {
            await using var command = _context.Database.GetDbConnection().CreateCommand();
            command.CommandText = sql;

            //添加查询参数,参数化查询可以避免sql注入
            if (parameters.Any())
            {
                foreach (var parameter in parameters)
                {
                    var sqlParameter = new SqlParameter(parameter.Item1, parameter.Item2);
                    command.Parameters.Add(sqlParameter);
                }
            }

            await _context.Database.OpenConnectionAsync();
            await using var dbDataReader = await command.ExecuteReaderAsync();
            dataTable.Load(dbDataReader);

            return dataTable;
        }
        catch (Exception e)
        {
            throw;
        }
    }

2. DataTable扩展方法,ToList<T>.

public static List<T> ToList<T>(this DataTable table) where T : class, new()
    {
        var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
        //大写
        var propDict = properties.ToDictionary(p => p.Name.ToUpper(), p => p);

        var list = new List<T>();

        //遍历一行数据
        foreach (DataRow row in table.Rows)
        {
            var obj = new T();
            //大写
            foreach (DataColumn column in table.Columns)
            {
                if (propDict.TryGetValue(column.ColumnName.ToUpper(), out var prop))
                {
                    if (prop.CanWrite)
                    {
                        var value = row[column.ColumnName];
                        //null的时候也可以考虑给其设置默认值
                        prop.SetValue(obj, value == DBNull.Value ? null : value);
                    }
                }
            }

            list.Add(obj);
        }

        return list;
    }

使用:

string sql =
            "select p.projectName,s.serviceName from [Project] p join  [service] s on s.projectId=p.ProjectId where p.ProjectId=@ProjectId ";
        var dataTable = await _wrapper.ProjectRepository.ExecuteSqlWithAdo(sql, [new("@ProjectId", "1")]);
        dataTable.ToList<Project>();


通过以上步骤就可以简单实现单表的自动ORM了,避免我们手动进行row, column 重复代码映射了。

此外本博主仍然实现了带层级的ORM,但是由于并不是全自动的,对sql书写有比较严格的要求,如果大家有什么更好的实现带层级的想法,欢迎交流沟通。

以上就是此篇文章的全部。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值