EF Core在mysql中调用存储过程
EF Core调用Mysql中的存储过程,驱动为Pomelo.EntityFrameworkCore.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();
}