繁体   English   中英

.NET 核心实体框架存储过程

[英].NET Core Entity Framework stored procedures

我正在尝试将 ASP.NET 4.5 应用程序移植到 .NET 核心,但我有一个我似乎无法弄清楚的实际问题。

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

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

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

目前,执行返回数据的存储过程的方式是使用DbSet.FromSql方法。

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

这有一定的局限性:

  • 它必须在DbSetDbSet
  • 返回的数据必须映射到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 查询返回即席类型的支持

Plain ADO.NET 使用存储过程的代码如下。 通过使用数据适配器:

            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;
                }
            } 

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

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

启动文件

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)));
            }
        }
    }
}

要使用多个数据集回答@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;
                }

            }
        }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM