2017-02-21 3 views
-2

Ich habe ein folgenden Code wie unten geschrieben:LINQ Union nicht ordnungsgemäß funktioniert

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(); 

Grundsätzlich ist dieser Code, was tut, ist Gruppen mein avalilable stammt aus dem DB-Tabelle und summiert die Werte für die gruppierten Tage.

Bitte beachten Sie folgenden Teil des Codes:

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

Ich versuche, die fehlenden Daten hinzuzufügen, die in meiner DB nicht existieren. So zum Beispiel wenn ich haben Termine wie diese:

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

Nun würde der Ausgang die fehlenden Tage + diejenigen, die bereits vorhanden sind ab dem heutigen Datum (das 21. Februar 2017 ist);

Ausgang sollte sein:

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 

Daten, die nicht in der Liste vorhanden sind, zugewiesenen Wert von 0, wie Sie sehen können ...

Other than that, allStoreItems ist eine Liste getippt von StoreItems und wie man sehen kann ich einen neuen Typ (eine benutzerdefinierte Klasse erstellen, die ich gerade gemacht, diese zwei Eigenschaften auf der Ansicht anzuzeigen;

der Fehler, den ich hier bekommen:

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> 

Was mache ich falsch, wie kann ich das beheben?

+2

verwendet werden könnte Es wäre Es wäre viel einfacher, dir zu helfen, wenn du hier und da ein [mcve] anstatt nur Schnipsel bereitstellen könntest. Es ist besonders wenig hilfreich, dass sich das Stück, das Sie aus dem ersten Eintrag hervorgehoben haben, geändert hat (StoreAnalyticOrders vs StoreItemTransactions, OrderDate vs TransactionDate usw.). –

+1

(Ich rate auch dringend davon ab, 'DateTime 'zu verwenden.Jetzt "in serverseitigem Code, es sei denn, Sie * wollen wirklich * von der Zeitzone Ihres Servers abhängen.) –

+0

@JonSkeet Sollte ich DateTimeUTC.Now verwenden? P.S. Bestelldatum und Transaktionsdatum sind beide vom selben Typ, wenn Sie mich danach fragen. =) – User987

Antwort

1

Wenn Sie mit

 allStoreItems.Union(...) 

dann beginnen, was vom gleichen Typ wie allStoreItems sein muss folgt und weil es nicht ist, können Sie Ihre Fehler. Daher müssen Sie Ihre Union später verschieben. Der einfachste Weg, darüber nachzudenken, besteht darin, zwei Listen zu erstellen und sie dann zu kombinieren.

Angenommen, Sie Ihre Liste Unter der Annahme haben

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(); 

, dass die oben genannten Arbeiten und gibt Ihnen einen List<StoreAnalyticOrders> dann können Sie Ihre zweite Liste erhalten, indem

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

Sie dann diese Listen mit Union kombinieren können. Allerdings müssen Sie ein Verfahren schaffen, um anzuzeigen, dass Sie nur das Bestelldatum und ignorieren die AmountPaid

vergleichen wollen, dass so etwas wie

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(); 
    } 
} 

Dies kann wie

ViewBag.result = list1.Union(list2, new StoreAnalyticOrdersComparer()) 
         .OrderBy(a=>a.OrderDate).ToList(); 
Verwandte Themen