Ich habe ein System, das verschiedene Kriterien für Sales in der Datenbank gespeichert werden kann. Wenn die Kriterien geladen sind, werden sie verwendet, um eine Abfrage zu erstellen und alle zutreffenden Verkäufe zurückzugeben. Die Kriterien Objekte wie folgt aussehen:Erstellen dynamischer Abfrage in einer Schleife mit Ausdrucksbäumen
ReferenceColumn (die Spalte in der Sale Tabelle sie gelten)
MinValue (Minimalwert der Referenzspalte sein muss)
MaxValue (Maximalwert der Referenzspalte muss sein)
Eine Suche nach Sales erfolgt anhand einer Sammlung der oben genannten Kriterien. ReferenceColumns des gleichen Typs werden OR-verknüpft, und ReferenceColumns verschiedener Typen werden UND-verknüpft. So zum Beispiel, wenn ich hatte drei Kriterien:
ReferenceColumn: 'Preis', MinValue: '10', MaxValue: '20'
ReferenceColumn: 'Preis', MinValue: '80', MaxValue: ‚100 '
ReferenceColumn: 'Alter', MinValue: '2', MaxValue: '3'
die Abfrage sollte alle Verkäufe zurück, wo der Preis war zwischen 10-20 oder zwischen 80-100, aber nur, wenn diejenigen, Das Verkaufsalter liegt zwischen 2 und 3 Jahren.
Ich habe es implementiert, um eine SQL-Abfrage-String und unter Verwendung .FromSql Ausführung:
public IEnumerable<Sale> GetByCriteria(ICollection<SaleCriteria> criteria)
{
StringBuilder sb = new StringBuilder("SELECT * FROM Sale");
var referenceFields = criteria.GroupBy(c => c.ReferenceColumn);
// Adding this at the start so we can always append " AND..." to each outer iteration
if (referenceFields.Count() > 0)
{
sb.Append(" WHERE 1 = 1");
}
// AND all iterations here together
foreach (IGrouping<string, SaleCriteria> criteriaGrouping in referenceFields)
{
// So we can always use " OR..."
sb.Append(" AND (1 = 0");
// OR all iterations here together
foreach (SaleCriteria sc in criteriaGrouping)
{
sb.Append($" OR {sc.ReferenceColumn} BETWEEN '{sc.MinValue}' AND '{sc.MaxValue}'");
}
sb.Append(")");
}
return _context.Sale.FromSql(sb.ToString();
}
Und das ist tatsächlich ganz gut mit unserer Datenbank funktioniert, aber es ist nicht schön spielen mit anderen Sammlungen, besonders die InMemory-Datenbank verwenden wir für UnitTesting, also versuche ich es mit Ausdrucksbäumen neu zu schreiben, die ich noch nie zuvor benutzt habe. Bisher habe ich das bekommen:
Es wirft derzeit eine ArgumentException, wenn ich Expression.Lamda aufrufen. Dezimal kann dort nicht verwendet werden und es sagt, dass es Typ Sale will, aber ich weiß nicht, was ich dort für den Vertrieb setzen soll, und ich bin mir nicht sicher, ob ich hier überhaupt auf dem richtigen Weg bin. Ich bin auch besorgt, dass mein MasterExpression jedes Mal mit sich selbst dupliziert, anstatt anzuhängen, wie ich es mit dem String Builder getan habe, aber vielleicht wird das trotzdem funktionieren.
Ich suche nach Hilfe, wie diese dynamische Abfrage in eine Ausdrucksbaumstruktur umgewandelt wird, und ich bin für einen völlig anderen Ansatz offen, wenn ich hier aus bin.
Dose ursprünglichen Code Arbeit für Sie arbeiten? Das sollte nicht funktionieren und warum benutzt du 1 = 1 und 1 = 0? –
Ja, es funktioniert, wenn die Sammlung Teil eines DbContext mit SQL Server ist. 1 = 1 und 1 = 0 sind da, also kann ich AND '/' OR 'immer an den Query-String anhängen, ohne sich mit dem ersten Iterations-Spezialfall usw. befassen zu müssen. – Valuator
Versuchen Sie es mit LINQKit (http://www.albahari.org) .com/nutshell/linqkit.aspx), macht es viel einfacher. Die Seite sagt: Mit LINQKit können Sie: ... Prädikate dynamisch erstellen – Tom