【问题标题】:The LINQ Expression 'DbSet<> Could not be translated method 'System.DateTime.ToString' failed, After Migrated from ASP.NET Core 2.1 to .NET6从 ASP.NET Core 2.1 迁移到 .NET6 后,LINQ 表达式 \'DbSet<> 无法翻译方法 \'System.DateTime.ToString\' 失败
【发布时间】:2022-12-05 20:57:09
【问题描述】:

我已将我的项目 ASP.NET Core 2.1 迁移到 .NET6,但我的某些 LINQ 查询无法正常工作并出现以下错误:

System.InvalidOperationException Message=LINQ 表达式 'DbSet() .Where(p => p.PaymentDate.ToString("MMM-yyyy").Equals(__ToString_0) && p.PaymentType == "治疗费")' 无法翻译。附加信息:方法“System.DateTime.ToString”的翻译失败。 如果此方法可以映射到您的自定义函数, 要么以可以翻译的形式重写查询, 或者通过插入对“AsEnumerable”、“AsAsyncEnumerable”、“ToList”或“ToListAsync”的调用来显式切换到客户端评估。

这是我在 ASP.NET Core 2.1 中的家庭控制器代码,它以每月和每日报告的形式从数据库返回数据,并将它们显示在折线图和 ViewBag 中。此代码在 asp.net core 2.1 上运行良好,但在我迁移到 .NET6 后,它为我使用日期字符串格式的每一行 LINQ 查询代码提供了一个错误 例如:a.RegisterDate.Value.Date.ToString("MMM-yyyy").Equals(date.Value.ToString("MMM-yyyy")

这是我在 ASP.NET Core 2.1 中的家庭控制器代码,需要以 .NET6 LINQ 查询格式进行修改,请帮助我将所有这些代码从 asp.net core 2.1 修改为 .NET6 LINQ 查询,谢谢。

    public class HomeController : BaseController
{
    private readonly IMvcControllerDiscovery _mvcControllerDiscovery;
    private readonly IWebHostEnvironment _hostingEnvironment;
    public HomeController(HoshmandDBContext context, IWebHostEnvironment hostingEnvironment, IMvcControllerDiscovery mvcControllerDiscovery) : base(context)
    {
        _hostingEnvironment = hostingEnvironment;
        _mvcControllerDiscovery = mvcControllerDiscovery;
    }
    public IActionResult Index(DateTime? date = null)
    {
        date = date ?? GetLocalDateTime();
        ViewBag.date = date;
        // MonthlyTransectionList(date);
        ViewBag.CompletedPatients = _context.PatientTbs.Where(a => a.PatientStatus == "Completed" && !a.IsDeleted && a.RegisterDate.Value.Date.ToString("MMM-yyyy").Equals(date.Value.ToString("MMM-yyyy"))).Count();
        ViewBag.CheckupPatients = _context.PatientTbs.Where(a => a.PatientStatus == "Checkup" && !a.IsDeleted && a.RegisterDate.Value.Date.ToString("MMM-yyyy").Equals(date.Value.ToString("MMM-yyyy"))).Count();
        ViewBag.WorkingPatients = _context.PatientTbs.Where(a => a.PatientStatus == "Working" && !a.IsDeleted && a.RegisterDate.Value.Date.ToString("MMM-yyyy").Equals(date.Value.ToString("MMM-yyyy"))).Count();
        ViewBag.ClosedPatients = _context.PatientTbs.Where(a => a.PatientStatus == "Closed" && !a.IsDeleted && a.RegisterDate.Value.Date.ToString("MMM-yyyy").Equals(date.Value.ToString("MMM-yyyy"))).Count();
        ViewBag.NumberOfPatientRegisterd = _context.PatientTbs.Where(a => !a.IsDeleted && a.IsActive.Value).Count();
        ViewBag.NumberOfPatientRegisterdToday = _context.PatientTbs.Where(a => !a.IsDeleted && a.IsActive.Value && a.RegisterDate == GetLocalDateTime().Date).Count();
        ViewBag.DailyPatientIcomeTreatmentFee = _context.PatientPaymentHistories.Where(a => a.PaymentDate.ToString("MMM-dd-yyyy").Equals(GetLocalDateTime().ToString("MMM-dd-yyyy")) && a.PaymentType == "Treatment Fee").Sum(a => a.PaidAmount);
        ViewBag.DailyPatientIcomeVisitFee = _context.PatientPaymentHistories.Where(a => a.PaymentDate.ToString("MMM-dd-yyyy").Equals(GetLocalDateTime().ToString("MMM-dd-yyyy")) && a.PaymentType == "Checkup Fee").Sum(a => a.PaidAmount);
        ViewBag.DailyClinicOut = _context.Expenses.Where(a => !a.IsDelete && a.ExpenseDate.Date == GetLocalDateTime().Date).Sum(a => a.ExpenseAmount)
            + _context.StockTransectionTbs.Where(a => a.TransectionDate.Value.Date == GetLocalDateTime().Date).Sum(a => a.TransectionAmount)
            + _context.PatientPaymentHistories.Where(a => a.PaymentDate.Date == GetLocalDateTime().Date && a.PaymentType == "Refund").Sum(a => a.PaidAmount)
            + _context.labsPayments.Where(a => a.PaymentDate.Date == GetLocalDateTime().Date).Sum(a => a.TotalPaid)
            + _context.EmployeeTransectionTbs.Where(a => !a.IsDeleted && a.TransectionDate.Value.Date == GetLocalDateTime().Date).Sum(a => a.TransectionAmount)
            + _context.OtherTransectionTbs.Where(a => !a.IsDeleted && a.TransectionType == "Debited" && a.TransectionDate.Value.Date == GetLocalDateTime().Date).Sum(a => a.TransectionAmount);
        ViewBag.TotalMainAccountAmount = _context.AccountTbs.FirstOrDefault().Amount;

        string[] monthName = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
        // patient chart registration
        ViewBag.PatientRegistrationStatisticsInCurrentYear = GetNumberOfPatientsPerMonthInCurrentYear(monthName);

        // transaction chart
        List<IncomeAndOutcome> incomeAndOutcomes = new List<IncomeAndOutcome>();
        var IncomePerMonthInCurrentYear = GetIncomePerMonthInCurrentYear(monthName);
        var OutcomePerMonthInCurrentYear = GetOutcomePerMonthInCurrentYear(monthName);
        foreach (var item in IncomePerMonthInCurrentYear)
        {
            incomeAndOutcomes.Add(new IncomeAndOutcome
            {
                month = item.Key,
                Income = item.Value,
                Outcome = OutcomePerMonthInCurrentYear.FirstOrDefault(a => a.Key == item.Key).Value
            });
        }
        ViewBag.IncomeAndOutcomeStatisticsInCurrentYear = incomeAndOutcomes;
        var _todayAppointments = _context.AppointmentTbs
            .Where(a => !a.IsDeleted && a.AppointmentDate.Value.ToString("MMM-yyyy") == date.Value.ToString("MMM-yyyy"))
            .GroupBy(a => a.SesstionGroup);

        List<TodayAppointment> todayAppointments = new List<TodayAppointment>();
        if (_todayAppointments.Any(a => a.FirstOrDefault().AppointmentStatus == 4))
        {
            todayAppointments.Add(new TodayAppointment
            {
                status = "Pending",
                count = _todayAppointments.Where(a => a.FirstOrDefault().AppointmentStatus == 4).Count()
            });
        }
        else
        {
            todayAppointments.Add(new TodayAppointment
            {
                status = "Pending",
                count = 0
            });
        }
        if (_todayAppointments.Any(a => a.FirstOrDefault().AppointmentStatus == 1))
        {
            todayAppointments.Add(new TodayAppointment
            {
                status = "Completed",
                count = _todayAppointments.Where(a => a.FirstOrDefault().AppointmentStatus == 1).Count()
            });
        }
        else
        {
            todayAppointments.Add(new TodayAppointment
            {
                status = "Completed",
                count = 0
            });
        }
        if (_todayAppointments.Any(a => a.FirstOrDefault().AppointmentStatus == 3))
        {
            todayAppointments.Add(new TodayAppointment
            {
                status = "Canceled",
                count = _todayAppointments.Where(a => a.FirstOrDefault().AppointmentStatus == 3).Count()
            });
        }
        else
        {
            todayAppointments.Add(new TodayAppointment
            {
                status = "Canceled",
                count = 0
            });
        }
        ViewBag.TodayAppointments = todayAppointments;

        return View();
    }
    private IActionResult MonthlyTransectionList(DateTime? date = null)
    {
        ViewBag.MonthlyPatientIcomeTreatmentFee = _context.PatientPaymentHistories.Where(a => a.PaymentDate.ToString("MMM-yyyy").Equals(date.Value.ToString("MMM-yyyy")) && a.PaymentType == "Treatment Fee").Sum(a => a.PaidAmount);
        ViewBag.MonthlyPatientIcomeVisitFee = _context.PatientPaymentHistories.Where(a => a.PaymentDate.ToString("MMM-yyyy").Equals(date.Value.ToString("MMM-yyyy")) && a.PaymentType == "Checkup Fee").Sum(a => a.PaidAmount);
        ViewBag.MonthlyExpenseOut = _context.Expenses.Where(a => !a.IsDelete && a.ExpenseDate.Date.ToString("MMM-yyyy").Equals(date.Value.ToString("MMM-yyyy"))).Sum(a => a.ExpenseAmount);
        ViewBag.MonthlyStockOut = _context.StockTransectionTbs.Where(a => a.TransectionDate.Value.Date.ToString("MMM-yyyy").Equals(date.Value.ToString("MMM-yyyy"))).Sum(a => a.TransectionAmount);
        ViewBag.MonthlyPatientRefunded = _context.PatientPaymentHistories.Where(a => a.PaymentDate.Date.ToString("MMM-yyyy").Equals(date.Value.ToString("MMM-yyyy")) && a.PaymentType == "Refund").Sum(a => a.PaidAmount);
        ViewBag.MonthlyLabOut = _context.labsPayments.Where(a => a.PaymentDate.Date.ToString("MMM-yyyy").Equals(date.Value.ToString("MMM-yyyy"))).Sum(a => a.TotalPaid);
        ViewBag.MonthlySalaryOut = _context.EmployeeTransectionTbs.Where(a => !a.IsDeleted && a.TransectionDate.Value.Date.ToString("MMM-yyyy").Equals(date.Value.ToString("MMM-yyyy"))).Sum(a => a.TransectionAmount);
        ViewBag.MonthlyDebitedTransectionOut = _context.OtherTransectionTbs.Where(a => !a.IsDeleted && a.TransectionType == "Debited" && a.TransectionDate.Value.Date.ToString("MMM-yyyy").Equals(date.Value.ToString("MMM-yyyy"))).Sum(a => a.TransectionAmount);
        ViewBag.MonthlyCreditedTransectionOut = _context.OtherTransectionTbs.Where(a => !a.IsDeleted && a.TransectionType == "Credited" && a.TransectionDate.Value.Date.ToString("MMM-yyyy").Equals(date.Value.ToString("MMM-yyyy"))).Sum(a => a.TransectionAmount);
        return View();
    }
    private PatientRegistrationStatisticsInCurrentYear GetNumberOfPatientsPerMonthInCurrentYear(string[] monthName)
    {
        var PatientsInCurrentYear = _context.PatientTbs.Where(a => !a.IsDeleted && a.IsActive.Value && a.RegisterDate.Value >= new DateTime(GetLocalDateTime().Year, 1, 1).Date);
        PatientRegistrationStatisticsInCurrentYear patientRegistrationStatisticsInCurrentYear = new PatientRegistrationStatisticsInCurrentYear
        {
            totalPatient = PatientsInCurrentYear.Count(),
            year = new DateTime(GetLocalDateTime().Year, 1, 1).Year,
            PatientPerMonth = new Dictionary<string, int>()
        };
        foreach (var item in monthName)
        {
            patientRegistrationStatisticsInCurrentYear.PatientPerMonth[item] = PatientsInCurrentYear.Where(a => a.RegisterDate.Value.ToString("MMM") == item).Count();
        }
        return patientRegistrationStatisticsInCurrentYear;
    }
    private Dictionary<string, decimal> GetIncomePerMonthInCurrentYear(string[] monthName)
    {
        Dictionary<string, decimal> Income = new Dictionary<string, decimal>();
        foreach (var month in monthName)
        {
            var income = _context.PatientPaymentHistories
                .Where(a => a.PaymentDate.Date >= new DateTime(GetLocalDateTime().Year, 1, 1) && !a.IsDeleted &&
                 !string.Equals(a.PaymentType, "Refund", StringComparison.CurrentCultureIgnoreCase)
                 && a.PaymentDate.ToString("MMM") == month).Sum(a => a.PaidAmount)
                + _context.OtherTransectionTbs.Where(a => a.TransectionDate.Value.Date >= new DateTime(GetLocalDateTime().Year, 1, 1)
                 && !a.IsDeleted && string.Equals(a.TransectionType, "Credited", StringComparison.CurrentCultureIgnoreCase)
                 && a.TransectionDate.Value.ToString("MMM") == month).Sum(a => a.TransectionAmount);
            Income.Add(month, income.Value);
        }
        return Income;
    }
    private Dictionary<string, decimal> GetOutcomePerMonthInCurrentYear(string[] monthName)
    {
        Dictionary<string, decimal> outcome = new Dictionary<string, decimal>();
        foreach (var month in monthName)
        {
            var og = _context.Expenses.Where(a => !a.IsDelete && a.ExpenseDate.Date >= new DateTime(GetLocalDateTime().Year, 1, 1) && a.ExpenseDate.ToString("MMM") == month).Sum(a => a.ExpenseAmount)
             + _context.StockTransectionTbs.Where(a => a.TransectionDate.Value.Date >= new DateTime(GetLocalDateTime().Year, 1, 1) && a.TransectionDate.Value.ToString("MMM") == month).Sum(a => a.TransectionAmount)
             + _context.PatientPaymentHistories.Where(a => a.PaymentDate.Date >= new DateTime(GetLocalDateTime().Year, 1, 1) && a.PaymentDate.ToString("MMM") == month && a.PaymentType == "Refund").Sum(a => a.PaidAmount)
             + _context.labsPayments.Where(a => a.PaymentDate.Date >= new DateTime(GetLocalDateTime().Year, 1, 1) && a.PaymentDate.ToString("MMM") == month).Sum(a => a.TotalPaid)
             + _context.EmployeeTransectionTbs.Where(a => !a.IsDeleted && a.TransectionDate.Value.Date >= new DateTime(GetLocalDateTime().Year, 1, 1) && a.TransectionDate.Value.ToString("MMM") == month).Sum(a => a.TransectionAmount)
             + _context.OtherTransectionTbs.Where(a => !a.IsDeleted && a.TransectionType == "Debited" && a.TransectionDate.Value.Date >= new DateTime(GetLocalDateTime().Year, 1, 1) && a.TransectionDate.Value.ToString("MMM") == month).Sum(a => a.TransectionAmount);
            outcome.Add(month, og.Value);
        }
        return outcome;
    }
}
public class PatientRegistrationStatisticsInCurrentYear
{
    public int year { get; set; }
    public int totalPatient { get; set; }
    public Dictionary<string, int> PatientPerMonth { get; set; }
}

public class IncomeAndOutcome
{
    public string month { get; set; }
    public decimal Income { get; set; }
    public decimal Outcome { get; set; }
}
public class TodayAppointment
{
    public string status { get; set; }
    public int count { get; set; }
}

【问题讨论】:

    标签: c# linq .net-6.0 asp.net-core-2.1


    【解决方案1】:

    EF Core 2 启用了自动静默客户端评估,但在更高版本中被禁用 - 请参阅相应的breaking change

    旧行为

    在 3.0 之前,当 EF Core 无法将作为查询一部分的表达式转换为 SQL 或参数时,它会自动在客户端上计算表达式。默认情况下,客户端对可能昂贵的表达式的评估只会触发警告。

    新行为

    从 3.0 开始,EF Core 只允许在客户端计算顶级投影(查询中的最后一个 Select() 调用)中的表达式。当查询的任何其他部分中的表达式无法转换为 SQL 或参数时,将抛出异常。

    作为快速修复,您在客户端explicitly evaluate(通过AsEnumerableToList 以及它们的异步对象),但总的来说,我认为您应该考虑重写查询,以便将它们转换为 SQL(基于您的数据库应该根据异常消息查看支持的函数映射,例如 here for SQL Server,您应该查看使用正确的日期时间函数,比较日期部分)。

    【讨论】:

      猜你喜欢
      • 2022-10-20
      • 2020-09-29
      • 2022-12-05
      • 1970-01-01
      • 2019-03-03
      • 2020-04-11
      • 1970-01-01
      • 2021-12-28
      • 1970-01-01
      相关资源
      最近更新 更多