2009-06-18 7 views
5

O forse c'è un modo migliore.Posso passare in T.Property? Inoltre, idee per migliorare questo metodo?

Sto costruendo un generatore di query dinamico per NHibernate, non vogliamo mettere HQL direttamente nell'applicazione, lo vogliamo come agnostico ORM possibile. Ecco come si presenta attualmente:

public override IEnumerable<T> SelectQuery(Dictionary<string, string> dictionary) 
    { 
     string t = Convert.ToString(typeof (T).Name); 
     string criteria = string.Empty; 
     foreach (KeyValuePair<string, string> item in dictionary) 
     { 
      if (criteria != string.Empty) 
        criteria += " and "; 


      criteria += item.Key + " = '" + item.Value + "'"; 
     } 

     string query = " from " + t; 

     if (criteria != string.Empty) 
      query += " where " + criteria; 

     return FindByHql(query); 
    } 

ok, grande, tuttavia .... ci sono due cose qui dentro che pongono un problema:

  1. Questa query solo maniglie "e," il mio primo il pensiero è di passare è costruire un metodo per costruire dinamicamente il dizionario che prende il nome della proprietà, il valore e un operatore "e" o "o" e costruisce il dizionario insieme a un array di operatori. Suona come la cosa giusta da fare?

  2. Ok, quindi, questo funziona GRANDE, tuttavia, quando c'è un intero fallisce a causa delle virgolette singole. Quello che penso sarebbe il modo migliore è avere il dizionario accetta <T.Property, string> e quindi riflettere in T.Property per trovare il tipo di dati e comportarsi di conseguenza. Sono troppo complicato?

Grazie.

risposta

3

Che dire di qualcosa del genere.

Dove hai un enum per l'operazione. Invece di passare una stringa per il dizionario, si passa un tipo di QueryObject che ha il tipo del valore e un'operazione per il valore. Puoi vedere qui sotto.

public enum Operation 
{ 
    And, 
    Or 
} 

public class QueryObject 
{ 
    public string Value { get; set; } 
    public Type Type { get; set; } 
    public Operation Operation { get; set; } 
} 

public override IEnumerable<T> SelectQuery(Dictionary<string, QueryObject> dictionary) 
{ 
    string t = Convert.ToString(typeof(T).Name); 
    string criteria = string.Empty; 
    foreach (KeyValuePair<string, QueryObject> item in dictionary) 
    { 
     if (!string.IsNullOrEmpty(criteria)) 
     { 
      switch (item.Value.Operation) 
      { 
       case Operation.And: 
        criteria += " and "; 
        break; 
       case Operation.Or: 
        criteria += " or "; 
        break; 
       default: 
        break; 
      } 
     } 

     if (item.Value.Type == typeof(int)) 
     { 
      criteria += item.Key + " = " + item.Value + " ";  
     } 
     else 
     { 
      criteria += item.Key + " = '" + item.Value + "'"; 
     } 
    } 

    string query = " from " + t; 

    if (criteria != string.Empty) 
     query += " where " + criteria; 

    return FindByHql(query); 
} 
+0

Ho usato questo, tranne che ho fatto via con il Dizionario tutti insieme e solo aggiunto "Proprietà" come stringa alla classe QueryObject. Grazie! Le query sui criteri –

1

Vorrei suggerire possibilmente creando una classe che ha tutte le proprietà necessari:

Name, 
Value, 
Type, 
JoinType (possibly an enum with Or/And) 

quindi, hanno il metodo di prendere una collezione di questi tipi al contrario di un dizionario. In questo modo, puoi facilmente controllare se hai bisogno di fare e/o, così come controllare se hai bisogno di preventivi ...

1

Il mio pensiero iniziale è che creare qualcosa del genere non è troppo ragionevole. Stai scrivendo il codice che genera HQL. Che a sua volta viene passato a Nhibernate che genera SQL.

Suggerirei di dare un'occhiata alle query di NHibernate . Innanzitutto come un modo più semplice per creare dinamicamente una query di NHibernate. Ma anche per darti un'idea di quanto possa essere complesso il rolling del tuo proprio generatore di query dinamico.

Detto questo. Se lo stavo facendo, probabilmente userei i criteri di NHibernate come base per qualsiasi tipo di generatore di query dinamico. Non c'è motivo per cui non possa generare una query da utilizzare da un altro ORM.

Una soluzione più generale al problema è di astrarre l'accesso ai dati in modo che se si desidera cambiare ORM, è sufficiente modificare il codice dietro l'astrazione. Questo è più lavoro, ovviamente, ma non sono convinto che mantenere il codice di accesso ai dati ORM indipendente sia qualcosa di particolarmente importante.

+0

sono un buon modo per andare, ma sono rimasto con la mia configurazione attuale nello spirito di "ottenere s ** t done" –

0

Bene, un'alternativa a ciò che si sta facendo è passare un'espressione> anziché il dizionario e quindi analizzare l'espressione di Linq per quello che si desidera. Un piccolo suggerimento che vorrei fare è utilizzare una query di criteri anziché HQL. Naturalmente analizzare l'espressione di Linq è probabilmente molto più complesso di quello che hai qui.

si può essere in grado di elaborare il dizionario e fare grandi HQL, ma fa male la testa pensando di fare in questo modo. Le richieste di criteri sembrano progettate per questo genere di cose.