【问题标题】:How to get a list of objects from a stored procedure in EF Core?如何从 EF Core 中的存储过程中获取对象列表?
【发布时间】:2020-10-29 13:37:09
【问题描述】:

我有一个存储过程,它获取多个参数并基于它们调用另一个存储过程。 返回的列可能会根据实际调用的存储过程而有所不同。

所以我构建了一个包含所有共享列的基类,并使用不同的类对其进行扩展,每个类都有自己的附加列作为要从存储过程返回的数据的模型。

以下是类示例:

public class SP_BaseModel
{
    public decimal? Sum { get; set; }
    public string Name { get; set; }
    public DateTime? BirthDate { get; set; }
}

public class SP_Extended1 : SP_BaseModel
{
    public int? Age { get; set; }
    public string Hobby { get; set; }
}

我正在像这样在 DbContext 中注册上述模型:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<SP_BaseModel>().HasNoKey();
    modelBuilder.Entity<SP_Extended1>();
    ...
}

我尝试了以下两种方法,但都不起作用:

public IQueryable<T> GetData<T>(string param1, int? patam2 = null, DateTime? param3 = null) where T : SP_BaseModel
{
    return Context.Set<T>()
                  .FromSqlInterpolated($"EXEC SP_GetData {param1},{param2 ?? null},{param3 ?? null}");
}


public async Task<List<T>> GetData<T>(string param1, int? patam2 = null, DateTime? param3 = null) where T : SP_BaseModel
{
    return Context.Set<T>()
                  .FromSqlInterpolated($"EXEC SP_GetData {param1},{param2 ?? null},{param3 ?? null}").ToListAsync();
}

我正在从中创建一个 Nuget,并在客户端中使用它:

public List<SP_Extended1> GetData(DateTime? today = null)
{
    today ??= DateTime.Today;
    
    //This didn't work
    var list1 = unitOfWork.MyRepository.GetData<SP_Extended1>(...);
    
    //This didn't work as well
    var list2 = unitOfWork.GetData<SP_Extended1>(...).AsEnumerable();

    return ...
}

但我收到此错误消息:

'FromSqlRaw or FromSqlInterpolated was called with non-composable SQL and with a query composing over it.
Consider calling `AsEnumerable` after the FromSqlRaw or FromSqlInterpolated method to perform the composition on the client-side.'

【问题讨论】:

标签: c# .net-core entity-framework-core


【解决方案1】:

这里尽量不要使用继承。将 SP_Extended1 与基类合并。 EF 不喜欢继承类。通常需要大量血液才能使其发挥作用。更容易使用独立的类。这是一个示例:

我写了一个特殊的类来从存储过程中获取数据

public class AccDef
{
    public string AccDefName { get; set; }
    public string InvoiceNumber { get; set; }
    public DateTime InvoiceDate { get; set; }
    public DateTime DeliveryDate { get; set; }
    public string ZoneName { get; set; }
    public double? Quantity { get; set; }
    public double HaulawayAmount { get; set; }
    public double FuelAmount { get; set; }
    public double SumAmount { get; set; }

    [NotMapped]
    public string StrQuantity
    {
        get { return Quantity == null || Quantity == 0 ? "-" : string.Format("{0:F0}", Quantity); }
    }

    [NotMapped]
    public string StrInvoiceDate
    {
        get { return InvoiceDate.ToString("dd/MM/yyyy"); }
    }

    [NotMapped]
    public string StrDeliveryDate
    {
        get { return DeliveryDate.ToString("dd/MM/yyyy"); }
    }
}

EF 上下文

        modelBuilder.Entity<AccDef>(e =>
        {
            e.HasNoKey();
        });

这是我使用 EF 从存储过程中获取数据的代码:

public async Task<IEnumerable<AccDef>> GetAccDefReportDetailsData(DateTime endDate)
{
    var pEndDate = new SqlParameter("@EndDate", endDate);

    return await _context.Set<AccDef>()
             .FromSqlRaw("Execute sp_GetAccDefReportDetails  @EndDate", parameters: new[] { pEndDate })
            .ToArrayAsync();
}

在此之后,我将此数组转换为我的 EF 模型实体列表。

【讨论】:

  • 问题是,我有大约 20 个不同的模型,它们都具有相同的 15 个字段,除了 3 个具有额外 2-3 个字段的模型。所以复制常见的 15 个字段看起来很痛苦。你确定没有别的办法吗?
  • 有办法的。如果你谷歌,你肯定会找到它。我记得我在一年前就尝试过,但是它太复杂了,需要配置很多东西,所以我决定复制粘贴几个类会更便宜。也许您可以在从 sp 获取数据后将数据转换回一个基类。
  • 我只为 sp 创建了几个特殊类。一些 SP 只是为了兼容性而返回了几个空字段。在此之后,我将这些 sp 分类数据转换回我的主模型。您可以考虑为此使用反射。
  • 你有一个代码示例来说明我如何在数据表中或任何其他方式中获取数据,然后是硬编码的类对象?
  • 是的,请查看我编辑的答案,如果您需要更多信息,请告诉我
猜你喜欢
  • 1970-01-01
  • 2022-11-27
  • 2021-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-06
  • 2017-10-11
  • 1970-01-01
相关资源
最近更新 更多