【问题标题】:.NET Core Entity Framework stored procedures.NET Core Entity Framework 存储过程
【发布时间】:2016-11-04 04:47:59
【问题描述】:

我正在尝试将 ASP.NET 4.5 应用程序移植到 .NET Core,但我遇到了一个我似乎无法弄清楚的真正问题。

我现有的应用程序执行存储的过程,它返回具有多个数据表的数据集。实体框架可以自动将返回的字段映射到我的实体属性,但仅适用于数据集中的第一个数据表(自然)。

所以我只是想弄清楚是否有可能以某种方式拦截模型构建过程并使用自定义代码来处理数据集并查看其他数据表以设置实体字段。

我知道我可以使用SqlConnection 直接执行存储过程的正常方式,但我想知道实体框架是否已经有一些方法可以做到这一点。

【问题讨论】:

  • 也许这个答案有帮助? stackoverflow.com/a/9987939/968301
  • 所以我刚刚注意到 DataTable 和 DataSet 以及它们所有的朋友在 .NET Core 中不受支持,因为它们被认为是遗留的。所以我必须改用 DbReader。我的假设是否正确?
  • 我认为您可以通过这种方式执行您的存储过程:dbContext.TableName.FromSql("stored_proc") 我不确定这是否会映射其他表中的所有字段。

标签: c# stored-procedures asp.net-core entity-framework-core


【解决方案1】:

目前,返回数据的the way to execute stored procedures是使用DbSet.FromSql方法。

using (var context = new SampleContext())
{
    var data= context.MyEntity
        .FromSql("EXEC GetData")
        .ToList();
}

这有一定的局限性:

  • 必须在DbSet 上调用它
  • 返回的数据必须映射到DbSet类型的所有属性
  • 它不支持临时对象。

或者您可以回退到普通的 ADO.NET:

using (var context = new SampleContext())
using (var command = context.Database.GetDbConnection().CreateCommand())
{
    command.CommandText = "GetData";
    command.CommandType = CommandType.StoredProcedure;
    context.Database.OpenConnection();
    using (var result = command.ExecuteReader())
    {
        // do something with result
    }
}

在某个阶段有来自 SQL 查询的plans to introduce support for returning ad hoc types

【讨论】:

  • 这也是我从我所做的所有研究中得出的结论。解决我的问题的一种方法是引入一个 DAO 对象,该对象具有映射到从存储过程返回的所有字段的属性。然后使用可能的隐式转换将 DAO 转换为我的业务对象,应用所有必要的逻辑来转换字段等......
  • 剩下的一个问题是存储过程返回的多个数据集。我能解决的唯一方法是将存储过程分成两部分并单独调用它们,然后遵循上述 DAO 模式,并在服务层将 DAO 合并到我的业务对象中。它的效率可能有点低,因为我现在要进行两次调用而不是一次调用,但在某种程度上更干净,更具可读性。
  • 2018年好像还是缺少这个功能吧?
  • @Muflix 您可以使用查询类型:learnentityframeworkcore.com/query-types
【解决方案2】:

我使用了 https://github.com/verdie-g/StoredProcedureEFCore,EnterpriseLibrary.Data.NetCore,EFCor.SqlServer,EFCore.Tools 的 StoredProcedureEFCore nuget 包

我尝试使用 {Repository pattern} 的 DbFirst 方法.. 我想是的

startup.cs

ConfigureServices(IServiceCollection services){
    services.AddDbContext<AppDbContext>(opt => opt
                   .UseSqlServer(Configuration.GetConnectionString("SampleConnectionString")));
    services.AddScoped<ISomeDAL, SomeDAL>();

}
            
    public  class AppDbContext : DbContext{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
    {}
}

ISomeDAl 接口有{GetPropertiesResponse GetAllPropertiesByCity(int CityId);}

public class SomeDAL : ISomeDAL
{
     private readonly AppDbContext context;

     public SomeDAL(AppDbContext context)
         {
             this.context = context;
         }
     public  GetPropertiesResponse GetAllPropertiesByCity(int CityId)
     {
         //Create Required Objects for response 
         //wont support ref Objects through params
         context.LoadStoredProc(SQL_STATEMENT)
            .AddParam("CityID", CityId).Exec( r =>
             {
                  while (r.Read())
                  {

                       ORMapping<GenericRespStatus> orm = new  ORMapping<GenericRespStatus>();
                       orm.AssignObject(r, _Status);
                  }

                  if (r.NextResult())
                  {

                       while (r.Read())
                       {
                           Property = new Property();
                           ORMapping<Property> orm = new ORMapping<Property>();
                           orm.AssignObject(r, Property);
                           _propertyDetailsResult.Add(Property);
                       }
                  }    
           });
    return new GetPropertiesResponse{Status=_Status,PropertyDetails=_propertyDetailsResult}; 
    }
}

public class GetPropertiesResponse
{
     public GenericRespStatus Status;
     public List<Property> PropertyDetails;
     public GetPropertiesResponse()
         {
             PropertyDetails = new List<Property>();
         }
}
public class GenericRespStatus
{
     public int ResCode { get; set; }
     public string ResMsg { get; set; }
}
internal class ORMapping<T>
{
    public void AssignObject(IDataReader record, T myClass)
    {
        PropertyInfo[] propertyInfos = typeof(T).GetProperties();
        for (int i = 0; i < record.FieldCount; i++)
        {
            if (propertyInfos.Any(obj => obj.Name == record.GetName(i))) //&& record.GetValue(i) != DBNull.Value
            {
                propertyInfos.Single(obj => obj.Name == record.GetName(i)).SetValue(myClass, Convert.ChangeType(record.GetValue(i), record.GetFieldType(i)));
            }
        }
    }
}

【讨论】:

  • 请阅读editing help 并了解如何正确设置答案和问题的格式。另外,请不要在多个问题上粘贴相同的答案。如果两个问题可以用相同的答案回答,您应该回答一个并将另一个标记为重复。
【解决方案3】:

普通 ADO.NET 代码将如下使用存储过程。通过使用 DataAdaptor:

            DataSet dataSet = null;

            using (var context = new SampleContext())
            using (var command = context.Database.GetDbConnection().CreateCommand())
            {
                command.CommandText = "GetData";
                command.CommandType = CommandType.StoredProcedure;
                context.Database.OpenConnection();
                using (SqlDataAdapter adapter = new SqlDataAdapter())
                {
                    adapter.SelectCommand = command;

                    dataSet = new DataSet();
                    adapter.Fill(dataSet);
                    return dataSet;
                }
            } 

【讨论】:

    【解决方案4】:

    要回答@DKhanaf 的多个数据集问题,您可以使用 SqlDataAdapter 用所有结果集填充 DataSet 对象。不过,SqlDataAdapter 需要完整的 .NET Framework,因此您必须在面向 .NET 462 或类似的东西时运行您的 .NETCore 项目。

             using (var context = new SampleContext())
                using (var command = context.Database.GetDbConnection().CreateCommand())
                {
                    command.CommandText = "GetData";
                    command.CommandType = CommandType.StoredProcedure;
                    context.Database.OpenConnection();
                    using (SqlDataAdapter adapter = new SqlDataAdapter(command))
                    {
                        var ds = new DataSet();
                        adapter.Fill(ds);
                        return ds;
                    }
    
                }
            }
    

    【讨论】:

    • context.Database.GetDbConnection().CreateCommand() 返回与SqlDataAdapter不兼容的DbCommand对象
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-13
    • 2018-04-25
    • 2020-03-05
    • 1970-01-01
    • 2020-05-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多