2017-02-21 5 views
-2

Я написал следующий код, как показано ниже:LINQ Союз не работает должным образом

ViewBag.result = allStoreItems.Union(Enumerable.Range(1, 30) 
      .Select(offset => new StoreAnalyticOrders { OrderDate = DateTime.Now.AddDays(-(30)).AddDays(offset), AmountPaid = 0 })) 
       .SelectMany(x => x.StoreItemTransactions) 
       .GroupBy(x => x.TransactionDate.Value.Date) 
       .Select(cl => new StoreAnalyticOrders { 
        OrderDate = cl.Key, 
        AmountPaid = cl.Sum(c => c.TransactionPrice) 
       }) 
       .OrderBy(x => x.OrderDate.Date) 
       .ToList(); 

В основном то, что этот код делает группа моим avalilable даты из таблицы БД и суммирует значения для сгруппированных дней.

Пожалуйста, обратите внимание на следующую часть кода:

.Union(Enumerable.Range(1, 30) 
.Select(offset => new StoreItemTransactions { TransactionDate = DateTime.Now.AddDays(-(30)).AddDays(offset), TransactionPrice = 0 })) 

Я пытаюсь добавить эти пропущенные даты, которые не существуют в моей БД. Так, например, если я есть даты, как это:

Date   Amount 
21 Feb. 2017 (some amount here) 
19 Feb. 2017 
13 Feb. 2017 

Теперь результат будет пропавшие дней + те, которые уже существуют с сегодняшнего дня (который 21 февраля 2017);

Вывод должен быть:

Date    Amount 
21 Feb. 2017 (some amounts here) 
20 Feb. 2017 
19 Feb. 2017 
18 Feb. 2017 
17 Feb. 2017 
16 Feb. 2017 
15 Feb. 2017 
14 Feb. 2017 
13 Feb. 2017 
12 Feb. 2017 
11 Feb. 2017 
10 Feb. 2017 
... all the way back to 21 Feb. -30 days 

Даты, которые не присутствуют в списке присваивается значение 0, как вы можете видеть ...

Кроме этого, allStoreItems это список набран из StoreItems и как вы можете видеть, я создаю новый тип (пользовательский класс, который я сделал только для отображения этих 2 свойств на View,

ошибка, что я получаю здесь:

List<StoreItems> does not contain a definition for 'Union' and the best extension method overload Queryable.Union<StoreAnalyticOrders>(IQueryable<StoreAnalyticOrders>) requires a receiver of Type IQueryable<StoreAnalyticOrders> 

Что я делаю неправильно, как я могу это исправить?

+2

Было бы гораздо проще помочь вам, если вы можете предоставить [mcve], а не просто фрагменты здесь и там. Особенно бесполезно, что часть, которую вы предположительно выделили из первого листинга, изменилась (StoreAnalyticOrders vs StoreItemTransactions, OrderDate vs TransactionDate и т. Д.). –

+1

(Я также * настоятельно рекомендую использовать 'DateTime.Теперь 'в серверном коде, если вы * действительно * не хотите зависеть от часового пояса вашего сервера по умолчанию.) –

+0

@JonSkeet Должен ли я использовать DateTimeUTC.Now? Постскриптум Дата заказа и TransactionDate являются одинаковыми, если это то, о чем вы меня спрашиваете? =) – User987

ответ

1

Если начать с

 allStoreItems.Union(...) 

то, что следует нужно быть того же типа, как allStoreItems и потому, что это не так, вы получите свою ошибку. Следовательно, вам нужно переместить свой союз позже. Самый простой способ подумать об этом - построить два списка, а затем объединить их.

Предположим, у вас есть список

var list1 = allStoreItems 
      .SelectMany(x => x.StoreItemTransactions) 
      .GroupBy(x => x.TransactionDate.Value.Date) 
      .Select(cl => new StoreAnalyticOrders { 
       OrderDate = cl.Key, 
       AmountPaid = cl.Sum(c => c.TransactionPrice) 
      }) 
      .OrderBy(x => x.OrderDate.Date) 
      .ToList(); 

Предполагая, что вышеуказанные работы и дает вам List<StoreAnalyticOrders>, то вы можете получить свой второй список,

var list2 = Enumerable.Range(1, 30) 
     .Select(offset => new StoreAnalyticOrders { OrderDate = DateTime.UtcNow.Date.AddDays(-(30)).AddDays(offset), AmountPaid = 0 }).ToList(); 

Вы можете объединить эти списки, используя соединение. Однако вам необходимо создать метод, чтобы указать, что вы хотите только сравнить OrderDate и игнорировать AmountPaid

Это может быть что-то вроде

public class StoreAnalyticOrdersComparer : IEqualityComparer<StoreAnalyticOrders> 
{ 
    bool IEqualityComparer<StoreAnalyticOrders>.Equals(StoreAnalyticOrders s1, StoreAnalyticOrders s2) 
    { 
     return s1.OrderDate == s2.OrderDate; 
    } 

    int IEqualityComparer<StoreAnalyticOrders>.GetHashCode(StoreAnalyticOrders obj) 
    { 
     if (Object.ReferenceEquals(obj, null)) 
      return 0; 

     return obj.OrderDate.GetHashCode(); 
    } 
} 

Это может быть использован как

ViewBag.result = list1.Union(list2, new StoreAnalyticOrdersComparer()) 
         .OrderBy(a=>a.OrderDate).ToList(); 
Смежные вопросы