使用EF 6将两个最近的条目记录到两个给定日期

时间:2017-06-15 23:09:33

标签: c# .net entity-framework

(对不起,标题模糊,不知道该怎么做。)

这是.NET 4.7,EF 6.1。我有两张桌子:一套产品和一套历史价格。我需要编写一些代码,这些代码将获得所有产品的列表及其提供的两个日期(开始和结束)的价格。这本质上是一个报告,看看产品价格在两个日期之间的变化情况,但我只需要开始/结束价格,而不是介于两者之间的所有价格。

我能够想到的唯一方法就是下面的代码。我会运行两次 - 一次是开始日期,一次是结束日期 - 然后我将这两个列表加入到我需要的模型类型的一个列表中。我不能为我的生活弄清楚如何做到这一点。 我应该如何做到这一点?

简化的表格布局:

Product        HistoricalPrice
-------        ---------------
-Id            -Id
-Name          -ProductId
               -ModifiedAt
               -NewPrice

这是我尝试使用的代码。 Product是对HistoricalPrice Product ProductId的引用,它是该类的一部分,并以var historicalStartPrices = await _context.ProductHistoricalPrices // need to include the product itself .Include(p => p.Product) // only get prices that come before the start date .Where(p => p.ModifiedAt <= start) // order from most recent -> oldest by modified date .OrderByDescending(p => p.ModifiedAt) // group prices by the product ID .GroupBy(p => p.ProductId) // take only the first result for each product ID .Select(g => g.First()) // enumerate the results .ToListAsync(); 字段引用。我需要在此代码的最终结果中获取产品名称/ ID。

FirstOrDefault

该代码抛出此异常:

  

NotSupportedException:方法&#39; First&#39;只能用作最终查询操作。考虑使用方法&#39; FirstOrDefault&#39;在这个例子中反而。

如果我切换到Product,则所有import java.util.Scanner; import java.util.Arrays; public class DestinationPlanner { static Scanner keyboard = new Scanner(System.in); static int cityDistance, arrivalCity; static double gasCost, MPG, totalCost; static String userContinue, userSelection, departCity; static double [][] cityTable = { {0, 384, 706, 729, 744, 767, 605, 548, 492, 346}, {384, 0, 399, 628, 437, 473, 291, 714, 390, 244}, {706, 399, 0, 877, 47, 605, 110, 1086, 742, 640}, {729, 628, 877, 0, 914, 384, 825, 395, 259, 406}, {744, 437, 47, 914, 0, 609, 154, 1123, 780, 685}, {767, 473, 605, 384, 609, 0, 563, 708, 367, 420}, {605, 291, 110, 825, 154, 563, 0, 1002, 679, 533}, {548, 714, 1086, 395, 1123, 708, 1002, 0, 344, 469}, {492, 390, 742, 259, 780, 367, 679, 344, 0, 146}, {346, 244, 640, 406, 685, 420, 533, 469, 146, 0}, }; static String [] citySelection = {"Jacksonville, Fl", "Charlotte, NC", "Washington, DC", "Memphis, TN", "Baltimore, MD", "Louisville, KY", "Richmond, VA", "New Orleans, LA", "Birmingham, AL", "Atlanta, GA" }; public static void main(String[] args) { System.out.println("Welcome to the Southeast Destination Planner!" + "\nTo help you plan your trip this program will calculate" + "\nthe cost to travel between two popular Southeast cities" + "\nWill you continue?" + "\nEnter 'y' to continiue 'n' to quit"); userContinue = keyboard.nextLine().toLowerCase(); while ((userContinue.equals("y")) & (userContinue.equals("n"))){ userContinue = keyboard.nextLine().toLowerCase(); } while (userContinue.equals("n")) { System.out.println("The program will now terminate"); System.exit(0); } while (userContinue.equals("y")) { citySelection(); carInfo(); finalCost(); } } private static void citySelection() { System.out.println("\nGreat, let's start by determining the city you will be departing"); System.out.println("\nPlease choose from the following cities"); System.out.println("[0] Jacksonville, FL"); System.out.println("[1] Charlotte, NC"); System.out.println("[2] Washington, DC"); System.out.println("[3] Memphis, TNA"); System.out.println("[4] Baltimore, MD"); System.out.println("[5] Louisville, KY"); System.out.println("[6] Richmond, VA"); System.out.println("[7] New Orleans, LA"); System.out.println("[8] Birmingham, AL"); System.out.println("[9] Atlanta, GA"); System.out.println("\nWhere will your trip begin?"); departCity = keyboard.nextLine(); while (!(departCity.equals("1")) && !(departCity.equals("2")) && !(departCity.equals("3")) && !(departCity.equals("4")) && !(departCity.equals("5")) && !(departCity.equals("6")) && !(departCity.equals("7")) && !(departCity.equals("8")) && !(departCity.equals("9")) && !(departCity.equals("0"))){ System.out.println("Please enter a number 0 through 9"); departCity = keyboard.nextLine(); } System.out.println("\nYou have chosen to depart from " + citySelection[departCity]); } 都为空。

3 个答案:

答案 0 :(得分:0)

为什么需要将产品包含在产品历史价格中?这些表格不相关吗? 也许对代码进行简单修改有助于实现目标:

var historicalStartPrices = await _context.ProductHistoricalPrices;

// only get prices that come between start and end dates
.Where(p => p.ModifiedAt >= start && p.ModifiedAt <= end

// order from most recent -> oldest by modified date
.OrderByDescending(p => p.ModifiedAt)

// take only prices foreach products in ProductHistoricalPrices
.Select(g => g.NewPrice)

// enumerate the results
.ToListAsync();

答案 1 :(得分:0)

这可能会在您的代码中的其他位置引用,但是p.Product引用的是什么?我没有在你的表中看到这样的通用字段。

此外,如果您尝试获取需要在您要查询的字段旁边的ID的第一个结果。

假设第一个查询不是必需的,那么您的查询看起来可能相同:

.Where(p => p.ModifiedAt <= start)
.OrderByDescending(p => p.ModifiedAt)
.GroupBy(p => p.ProductId.First())
.ToListAsync();

如果你真的需要引用另一个表中的一个项目,你可以将该值存储在一个变量中,或者你可以简单地检索你最近的一个条目:`query.Where(p =&gt; p.ModifiedAt

答案 2 :(得分:0)

您的问题的解决方案(每个产品的初始价格和最终价格)是让您的Linq查询如下所示:

var historicalPrices = await _context.ProductHistoricalPrices.Where(x => x.ModifiedAt >= startDate && x.ModifiedAt <= endDate).Select(x => new
    {
     ProductId = x.ProductId,
     ProductName = x.Product.Name,
     Price = x.NewPrice,
     ModificationDate = x.ModifiedAt
    }).GroupBy(x => x.ProductId).Select(x => new
{
  ProductName = x.FirstOrDefault().ProductName,
  InitialPrice = x.OrderBy(x => x.ModificationDate).FirstOrDefault().Price,
  FinalPrice = x.OrderByDescending(x => x.ModificationDate).FirstOrDefault().Price
}).ToListAsync();