Per vari motivi, devo essere in grado di consentire all'utente di selezionare un elemento da un database in base alla scelta di colonne e valori. Ad esempio, se ho una tabella:LINQ Seleziona colonne e valori dinamici
Name | Specialty | Rank
-------+-----------------+-----
John | Basket Weaving | 12
Sally | Basket Weaving | 6
Smith | Fencing | 12
L'utente può richiedere un 1, 2, o più colonne e le colonne che richiedono può essere diverso. Ad esempio, l'utente può richiedere voci in cui Specialty == Basket Weaving
e Rank == 12. What I do currently is gather the user's request and create a list of
KeyValuePair where the
chiave is the column name and the
Value` è il valore desiderato della colonna:
class UserSearch
{
private List<KeyValuePair<string, string> criteria = new List<KeyValuePair<string, string>>();
public void AddTerm(string column, string value)
{
criteria.Add(new KeyValuePair<string, string>(column, value);
}
public void Search()
{
using (var db = new MyDbContext())
{
// Search for entries where the column's (key's) value matches
// the KVP's value.
var query = db.MyTable.Where(???);
}
}
}
/* ... Somewhere else in code, user adds terms to their search
* effectively performing the following ... */
UserSearch search = new UserSearch();
search.Add("Specialty", "Basket Weaving");
search.Add("Rank", "12");
Usando questa lista di KeyValuePair
's, come posso più succintamente selezionare le voci del database che corrisponde a tutti i criteri?
using (var db = new MyDbContext)
{
// Where each column name (key) in criteria matches
// the corresponding value in criteria.
var query = db.MyTable.Where(???);
}
MODIFICA: Vorrei utilizzare EntityFramework anziché SQL raw se posso aiutarlo.
UPDATE 3: Mi sto avvicinando. Ho scoperto un modo per utilizzare LINQ dopo aver scaricato tutti i valori dalla tabella. Questo ovviamente non è super ideale perché scarica tutto nella tabella. Quindi immagino che l'ultimo passo sarebbe quello di capire un modo in cui non devo scaricare l'intera tabella ogni volta. Ecco una spiegazione di quello che sto facendo:
Per ogni riga della tabella
db.MyTable.ToList().Where(e => ...
faccio una lista di Caccio che rappresentano se la colonna soddisfa i criteri.
criteria.Select(c => e.GetType()?.GetProperty(c.Key)?.GetValue(e)?.ToString() == c.Value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Basically just gets the value of specific column
by string
Poi ho controllare per vedere se questa lista bool è tutto vero
.All(c => c == true)
Un esempio del codice completo è qui sotto:
// This class was generated from the ADO.NET Entity Data Model template
// from the database. I have stripped the excess stuff from it leaving
// only the properties.
public class MyTableEntry
{
public string Name { get; }
public string Specialty { get; }
public string Rank { get; }
}
class UserSearch
{
private List<KeyValuePair<string, string> criteria = new List<KeyValuePair<string, string>>();
public void AddTerm(string column, string value)
{
criteria.Add(new KeyValuePair<string, string>(column, value);
}
public async Task<List<MyTableEntry>> Search()
{
using (var db = new MyDbContext())
{
var entries = await db.MyTable.ToListAsync();
var matches = entries.Where(e => criteria.Select(c => e.GetType()
?.GetProperty(c.Key)
?.GetValue(e)
?.ToString() == c.Value)
.All(c => c == true));
return matches.ToList();
}
}
}
Sembra come se il mio problema si trova con questo segmento di codice:
e.GetType()?.GetProperty(c.Key)?.GetValue(e)?.ToString()
Non ho familiarità con gli alberi delle espressioni, quindi forse la risposta sta in loro. Potrei anche provare Dynamic LINQ.
ritengo questo post ti aiuterà, http://stackoverflow.com/questions/821365/how-to-convert-a-string-to-its-equivalent-expression-tree Stai andando a dover convertire la stringa che vuoi nel punto Dove a un'espressione reale che funzionerà. – Dylan
Ho aggiornato la mia risposta per includere l'SQL generato da linq per alleviare i problemi relativi ai confronti non necessari in SQL. – Jakotheshadows
hai già risolto? –