EF Core在mysql中调用存储过程

EF Core在mysql中调用存储过程,博主找了很多,然而大多都是EF Core+SqlServer的或者EF Core+Oracle的,并没有正对Mysql的Pomelo驱动的,所以查找了一些资料和博文之后,进行一些修改,最终得到下面的代码。

1. 方式一【FromSql】

搜索到的基本上都这样的方式

using (var dataContext = new DbContext()) {
       var param = 1;
       var query = dataContext.Table.FromSql($"procname {param}");
       var result = query.ToList();
       Assert.NotNull(result);
   }

然而这种方式有两个弊端,一是Table必须是包含在DbContext中,这也就意味着要建一个对应的表在数据库中,二是这种查询在mysql的pomelo驱动中,会存在一些不完善,导致在数据库直接执行存储过程的结果和在EF Core中调用执行的结果不一致,且还会出现数据集结果全是一样的重复数据,所以这种方式在EF Core+Mysql中不能使用。

2. 方式二【ExecuteReader】

使用最基本的读取方式,这种方式基本上已经脱离了EF上下文,具体可以参考链接EF切EFCore2.0存储过程问题
不过博主的这篇文章是针对sqlserver的,mysql并不使用,所以我改写了一下使用ExecuteReader读取数据的过程,添加一个方法在DbContext类中,代码如下

///添加到EF上下文DbContext.cs中
/// <summary>
/// 执行sql查询
/// </summary>
/// <typeparam name="TElement">结果集类型</typeparam>
/// <param name="sql">执行语句</param>
/// <param name="parameters">参数</param>
/// <returns></returns>
public IEnumerable<TElement> SqlQuery<TElement>(string sql, params object[] parameters) where TElement : new()
{
    using (var content = new ETLDbContextFactory().CreateDbContext())
    {
        var connection = Database.GetDbConnection();
        using (var cmd = connection.CreateCommand())
        {
            Database.OpenConnection();
            cmd.CommandText = sql;
            cmd.CommandType = System.Data.CommandType.StoredProcedure;
            cmd.Parameters.AddRange(parameters);
            var dr = cmd.ExecuteReader();

            var data = new List<TElement>(); ;
            while (dr.Read())
            {
                TElement item = new TElement();
                Type type = item.GetType();
                foreach (var propertyInfo in type.GetProperties())
                {
                    //var propertyInfo = type.GetProperty(kv.Name);
                    //if (kv.GetConstantValue.HasValue && propertyInfo != null)
                    //{
                    //注意需要转换数据库中的DBNull类型
                    var value = dr.GetValue(dr.GetOrdinal(propertyInfo.Name));
                    propertyInfo.SetValue(item, value);
                    //}
                }
                data.Add(item);
            }
            dr.Dispose();
            return data;
        }
    }
}

调用

using (var content = new DbContext())
{
    //这个地方的调用存储过程,只需要传入存储过程名字,不用像mysql中还需要在前面加call,参数于存储过程的参数对应放在MySqlParameter数组中即可
    var result = content.SqlQuery<TableEntity>("get_tablelist_with_dbname", new MySql.Data.MySqlClient.MySqlParameter("dbname", "bfstock"));
    return result.ToList();
}