I am receiving the following error when testing to run a report:
LINQ to Entities does not recognize the method ‘System.Decimal PerformCurrencyConversion(System.Decimal, System.Decimal, System.Decimal, System.String, System.DateTime)’ method, and this method cannot be translated into a store expression.
Here is my query:
List<BusinessPlanningElements> productSales = (from sale in ctn.ProductSales
where sale.DateSold.Year == reportRequest.Year && sale.ProductID == t.ProductID
group sale by sale.DateSold.Month into ds
select new BusinessPlanningElements
{
Month = ds.Select(it => it.DateSold.Month).FirstOrDefault(),
EURNumberOfUnitSold = ds.Where(it => it.EURSales.HasValue).Where(it => it.EURSales != 0).Count(),
GBPNumberOfUnitSold = ds.Where(it => it.GBPSales.HasValue).Where(it => it.GBPSales != 0).Count(),
USDNumberOfUnitSold = ds.Where(it => it.USDSales.HasValue).Where(it => it.USDSales != 0).Count(),
EURCumulativeNumberOfUnitsSold = ctn.ProductSales.Where(it => it.EURSales.HasValue && it.EURSales != 0 && it.ProductID == t.ProductID && it.DateSold.Month <= ds.Key).Count(),
GBPCumulativeNumberOfUnitsSold = ctn.ProductSales.Where(it => it.GBPSales.HasValue && it.GBPSales != 0 && it.ProductID == t.ProductID && it.DateSold.Month <= ds.Key).Count(),
USDCumulativeNumberOfUnitsSold = ctn.ProductSales.Where(it => it.USDSales.HasValue && it.USDSales != 0 && it.ProductID == t.ProductID && it.DateSold.Month <= ds.Key).Count(),
USDTotalSales = PerformCurrencyConversion(ds.Sum(it => it.USDSales.HasValue ? it.USDSales.Value : 0), 0M, 0M, reportRequest.Currency, DateTime.Now.AddMonths(-2)),
GBPTotalSales = PerformCurrencyConversion(0M, ds.Sum(it => it.GBPSales.HasValue ? it.GBPSales.Value : 0), 0M, reportRequest.Currency, DateTime.Now.AddMonths(-2)),
EURTotalSales = PerformCurrencyConversion(0M, 0M, ds.Sum(it => it.EURSales.HasValue ? it.EURSales.Value : 0), reportRequest.Currency, DateTime.Now.AddMonths(-2)),
USDCumulativeTotalSales = PerformCurrencyConversion(ctn.ProductSales.Sum(it => it.USDSales.HasValue && it.USDSales != 0 && it.ProductID == t.ProductID && it.DateSold.Month <= ds.Key ? it.USDSales.Value : 0), 0M, 0M, reportRequest.Currency, DateTime.Now.AddMonths(-2)),
GBPCumulativeTotalSales = PerformCurrencyConversion(ctn.ProductSales.Sum(it => it.GBPSales.HasValue && it.GBPSales != 0 && it.ProductID == t.ProductID && it.DateSold.Month <= ds.Key ? it.GBPSales.Value : 0), 0M, 0M, reportRequest.Currency, DateTime.Now.AddMonths(-2)),
EURCumulativeTotalSales = PerformCurrencyConversion(ctn.ProductSales.Sum(it => it.EURSales.HasValue && it.EURSales != 0 && it.ProductID == t.ProductID && it.DateSold.Month <= ds.Key ? it.EURSales.Value : 0), 0M, 0M, reportRequest.Currency, DateTime.Now.AddMonths(-2)),
}).ToList();
The PerformCurrencyConversion method pretty much gets a list of conversion rates, and converts the value to the currency which is specified by the user. It accepts parameters like so:
public decimal PerformCurrencyConversion(decimal usd, decimal gbp, decimal eur, string Currency, DateTime saleMonth)
{
//Logic
}
I have used this method several times in the past throughout the codebase with no trouble or errors, e.g.
List<MonthlyProductSales> monthlyProductSales = (from sale in productSales
orderby sale.DateSold descending
group sale by new { sale.DateSold.Month, sale.Product.Name } into ds
select new MonthlyProductSales
{
Name = ds.Select(it => it.Product.Name).FirstOrDefault(),
Month = ds.Select(it => it.DateSold.Month).FirstOrDefault(),
Year = ds.Select(it => it.DateSold.Year).FirstOrDefault(),
USDNumberItemsSold = ds.Where(it => it.USDSales.HasValue).Where(it => it.USDSales != 0).Count(),
GBPNumberItemsSold = ds.Where(it => it.GBPSales.HasValue).Where(it => it.GBPSales != 0).Count(),
EURNumberItemsSold = ds.Where(it => it.EURSales.HasValue).Where(it => it.EURSales != 0).Count(),
USDRevenueTotal = PerformCurrencyConversion(ds.Sum(it => it.USDSales.HasValue ? it.USDSales.Value : 0), 0M, 0M, reportRequest.Currency, DateTime.Now.AddMonths(-2)),
GBPRevenueTotal = PerformCurrencyConversion(0M, ds.Sum(it => it.GBPSales.HasValue ? it.GBPSales.Value : 0), 0M, reportRequest.Currency, DateTime.Now.AddMonths(-2)),
EURRevenueTotal = PerformCurrencyConversion(0M, 0M, ds.Sum(it => it.EURSales.HasValue ? it.EURSales.Value : 0), reportRequest.Currency, DateTime.Now.AddMonths(-2)),
}).ToList();
Can anyone see what the difference is, or how I might get around this error?
The difference is in the LINQ implementation.
In the first code sample, you are using LINQ to Entities (i.e., the LINQ implementation of Entity Framework). This implementation translates your LINQ into SQL which is eventually executed on the database.
In the 2nd code sample, you are using LINQ to Objects (i.e., in-memory collections). This implementation does not translate to SQL or another language, but simply creates a chain of actions that are executed on in-memory collections. Therefore, this implementation of LINQ can use .NET functions such as
PerformCurrencyConversion.So what you can do is first query your database using LINQ to Entities, and store the results in an array or list, and then do a LINQ to Objects query on that array or list — and then you can use built-in .NET functions.