如何在Entity Framework中的嵌套实体上重用映射函数?

时间:2017-11-09 19:41:33

标签: c# entity-framework entity-framework-6

我见过多个与此类似的问题,但我认为我的情况略有不同。我正在使用EF6查询数据库,我正在使用数据投影来获得更好的查询。

鉴于性能在这个项目中非常重要,我必须确保只读取我将使用的实际字段,所以我有非常相似的查询,只有几个字段不同,因为我已经这样做了我注意到重复代码,所以我一直在思考如何重用代码,这是我目前所拥有的:

 public static IEnumerable<FundWithReturns> GetSimpleFunds(this DbSet<Fund> funds, IEnumerable<int> fundsId)
    {
        IQueryable<Fund> query = GetFundsQuery(funds, fundsId);

        var results = query
            .Select(f => new FundWithReturns
            {

                Category = f.Category,
                ExpenseRatio = f.ExpenseRatio,
                FundId = f.FundId,
                Name = f.Name,
                LatestPrice = f.LatestPrice,
                DailyReturns = f.FundDailyReturns
                                    .Where(dr => dr.AdjustedValue != null)
                                    .OrderByDescending(dr => dr.CloseDate)
                                    .Select(dr => new DailyReturnPrice
                                    {
                                        CloseDate = dr.CloseDate,
                                        Value = dr.AdjustedValue.Value,
                                    }),
                Returns = f.Returns.Select(r => new ReturnValues
                     {
                         Daily = r.AdjDaily,
                         FiveYear = r.AdjFiveYear,
                         MTD = r.AdjMTD,
                         OneYear = r.AdjOneYear,
                         QTD = r.AdjQTD,
                         SixMonth = r.AdjSixMonth,
                         ThreeYear = r.AdjThreeYear,
                         YTD = r.AdjYTD
                     }).FirstOrDefault()
            })
            .ToList();
        foreach (var result in results)
        {
            result.DailyReturns = result.DailyReturns.ConvertClosingPricesToDailyReturns();
        }
        return results;
    }

 public static IEnumerable<FundListVm> GetFundListVm(this DbSet<Fund> funds, string type)
    {
        return funds
                .Where(f => f.StatusCode == MetisDataObjectStatusCodes.ACTIVE
                 && f.Type == type)
                 .Select(f => new FundListVm

                 {
                     Category = f.Category,
                     Name = f.Name,
                     Symbol = f.Symbol,
                     Yield = f.Yield,
                     ExpenseRatio = f.ExpenseRatio,
                     LatestDate = f.LatestDate,
                     Returns = f.Returns.Select(r => new ReturnValues
                     {
                         Daily = r.AdjDaily,
                         FiveYear = r.AdjFiveYear,
                         MTD = r.AdjMTD,
                         OneYear = r.AdjOneYear,
                         QTD = r.AdjQTD,
                         SixMonth = r.AdjSixMonth,
                         ThreeYear = r.AdjThreeYear,
                         YTD = r.AdjYTD
                     }).FirstOrDefault()
                 }).OrderBy(f=>f.Symbol).Take(30).ToList();
    }

我正在尝试重用我映射f.Returns的部分,所以我尝试创建了一个Func&lt;&gt;如下:

private static Func<Return, ReturnValues> MapToReturnValues = r => new ReturnValues
    {
        Daily = r.AdjDaily,
        FiveYear = r.AdjFiveYear,
        MTD = r.AdjMTD,
        OneYear = r.AdjOneYear,
        QTD = r.AdjQTD,
        SixMonth = r.AdjSixMonth,
        ThreeYear = r.AdjThreeYear,
        YTD = r.AdjYTD
    };

然后像这样使用:

public static IEnumerable<FundListVm> GetFundListVm(this DbSet<Fund> funds, string type)
    {
        return funds
                .Where(f => f.StatusCode == MetisDataObjectStatusCodes.ACTIVE
                 && f.Type == type)
                 .Select(f => new FundListVm

                 {
                     Category = f.Category,
                     Name = f.Name,
                     Symbol = f.Symbol,
                     Yield = f.Yield,
                     ExpenseRatio = f.ExpenseRatio,
                     LatestDate = f.LatestDate,
                     Returns = f.Returns.Select(MapToReturnValues).FirstOrDefault()
                 }).OrderBy(f=>f.Symbol).Take(30).ToList();
    }

编译器没问题,但在运行时崩溃并说:内部.NET Framework数据提供程序错误1025

我尝试将Func转换为Expression,就像我读了一些问题,然后使用compile()但是它无法使用AsEnumerable也不是一个选项,因为它将首先查询所有字段,这是我想要的避免。

我在尝试一些不可能的事情吗?

感谢您的时间。

1 个答案:

答案 0 :(得分:1)

肯定需要Expression<Func<...>>。但是,不是使用Compile()方法(不支持),而是使用完全支持的AsQueryable()方法解决编译时错误(在EF6中,这个技巧在当前的EF Core中不起作用) )。

鉴于修改后的定义

private static Expression<Func<Return, ReturnValues>> MapToReturnValues =
    r => new ReturnValues { ... };

样本用法是

Returns = f.Returns.AsQueryable().Select(MapToReturnValues).FirstOrDefault()