我正在使用EF Core 3.1,并且具有以下存储过程调用:
public async Task<string> UserSessionGet(string user, string password, string ip)
{
IList<SessionItem> lst = null;
try
{
// Processing.
string sqlQuery = "EXEC [dbo].[GetUserSession] @UserLogin, @UserPassword, @IP, @ErrorCode OUTPUT, @ErrorText OUTPUT";
int errorCode = 0;
string errorText = string.Empty;
lst = await this.Set<SessionItem>().FromSqlRaw(sqlQuery,
new SqlParameter("@UserLogin", user ?? (object)DBNull.Value),
new SqlParameter("@UserPassword", password ?? (object)DBNull.Value),
new SqlParameter("@IP", ip ?? (object)DBNull.Value),
new SqlParameter("@ErrorCode", errorCode) { Direction = ParameterDirection.Output},
new SqlParameter("@ErrorText", errorText) { Direction = ParameterDirection.Output }
).ToListAsync();
}
catch (Exception ex)
{
throw ex;
}
// Info.
return lst.FirstOrDefault()?.Session;
}
实体:
public class SessionItem
{
[NotMapped]
public string Session { get; set; }
}
设置:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SessionItem>().HasNoKey();
}
当我尝试执行此代码时,会引发异常:
序列不包含任何元素
当我在失败登录尝试中删除NotMapped
注释时,我会收到异常
“ FromSql”操作的结果中没有所需的“会话”列
当用户输入错误的密码或用户名时,仅返回@ErrorCode
和@ErrorText
,但根本没有数据。
https://i.ibb.co/pf4KzHz/Failure-Login.png
成功调用后,仅返回一列,称为Session
。
https://i.ibb.co/tL3CR1H/2020-09-06-07-57-12.png
我该怎么办?
我还有另一个存储过程,具有不同的列集和相同的行为。
答案 0 :(得分:0)
我写了自己的扩展类:
public static class DataModelExtensions
{
public static DbCommand LoadStoredProc(
this DbContext context, string storedProcName)
{
var cmd = context.Database.GetDbConnection().CreateCommand();
cmd.CommandText = storedProcName;
cmd.CommandType = System.Data.CommandType.StoredProcedure;
return cmd;
}
public static DbCommand LoadSql(this DbContext context, string sql)
{
var cmd = context.Database.GetDbConnection().CreateCommand();
cmd.CommandText = sql;
cmd.CommandType = System.Data.CommandType.Text;
return cmd;
}
public static DbCommand WithSqlParam(this DbCommand cmd, string paramName, object paramValue, ParameterDirection direction = ParameterDirection.Input, int ?size = null)
{
if (string.IsNullOrEmpty(cmd.CommandText))
throw new InvalidOperationException(
"Call LoadStoredProc before using this method");
var param = cmd.CreateParameter();
param.ParameterName = paramName;
param.Value = paramValue;
param.Direction = direction;
if (size.HasValue)
param.Size = size.Value;
cmd.Parameters.Add(param);
return cmd;
}
private static List<T> MapToList<T>(this DbDataReader dr, int? errorCode, string errorText)
{
var objList = new List<T>();
var props = typeof(T).GetRuntimeProperties();
var colMapping = dr.GetColumnSchema()
.Where(x => props.Any(y => y.Name.ToLower() == x.ColumnName.ToLower()))
.ToDictionary(key => key.ColumnName.ToLower());
int rowNumber = 1;
T obj = Activator.CreateInstance<T>();
if (dr.HasRows)
{
while (dr.Read())
{
obj = Activator.CreateInstance<T>();
foreach (var prop in props)
{
if (colMapping.ContainsKey(prop.Name.ToLower()))
{
object val;
var propName = prop.Name.ToLower();
val = dr.GetValue(colMapping[propName].ColumnOrdinal.Value);
prop.SetValue(obj, val == DBNull.Value ? null : val);
}
}
rowNumber++;
objList.Add(obj);
}
}
else
{
foreach (var prop in props)
{
var propName = prop.Name;
if (propName == "ErrorCode")
prop.SetValue(obj, errorCode);
else if (propName == "ErrorText")
prop.SetValue(obj, errorText);
}
objList.Add(obj);
}
return objList;
}
public static async Task<List<T>> Execute<T>(this DbCommand command)
{
using (command)
{
//System.Diagnostics.Debug.WriteLine(command.ToLog());
if (command.Connection.State == System.Data.ConnectionState.Closed)
command.Connection.Open();
try
{
using (var reader = await command.ExecuteReaderAsync())
{
return reader.MapToList<T>((int?)command.Parameters["@ErrorCode"].Value, (string)command.Parameters["@ErrorText"].Value);
}
}
catch (Exception e)
{
throw (e);
}
finally
{
command.Connection.Close();
}
}
}
public static async Task<bool> HasRows(this DbCommand command)
{
using (command)
{
if (command.Connection.State == System.Data.ConnectionState.Closed)
command.Connection.Open();
try
{
using (var reader = await command.ExecuteReaderAsync())
{
return reader.HasRows;
}
}
catch (Exception e)
{
throw (e);
}
finally
{
command.Connection.Close();
}
}
}
public static async Task<bool> QueryHasRows(this DbContext context, string sql)
{
return await context.LoadSql(sql).HasRows();
}
public static string ToLog(this DbCommand command)
{
//-- @p5: Input Int (Size = -1; Prec = 0; Scale = 0) [194]
StringBuilder sb = new StringBuilder();
sb.AppendLine();
sb.AppendLine(command.CommandText);
foreach(DbParameter parameter in command.Parameters)
{
if(parameter.Value != null && !string.IsNullOrEmpty(parameter.Value.ToString()))
{
sb.AppendLine($"{parameter.ParameterName}={parameter.Value}");
//sb.AppendLine($"-- {parameter.ParameterName}: {parameter.Direction} {parameter.DbType} (Size = {parameter.Size}; Prec = {parameter.Precision}; Scale = {parameter.Scale}) [{parameter.Value}]");
}
}
return sb.ToString();
}
}
使用示例:
public async Task<string> UserSessionGet(string user, string password, string ip)
{
//SessionItem lst = null;
IList<SessionItem> lst = null;
try
{
int errorCode = 0;
string errorText = string.Empty;
List<SessionItem> result = new List<SessionItem>();
result = await this.LoadStoredProc("UserSessionGet")
.WithSqlParam("@UserLogin", user)
.WithSqlParam("@UserPassword", password)
.WithSqlParam("@IP", ip)
.WithSqlParam("@ErrorCode", errorCode, ParameterDirection.Output)
.WithSqlParam("@ErrorText", errorText, ParameterDirection.Output, 255)
.Execute<SessionItem>();
if (result.Count == 1)
{
return result[0].Session;
}
//return result.FirstOrDefault(x => x.iscurrent.ToLower() == "да");
return string.Empty;
}
catch (Exception ex)
{
throw ex;
}
}