2012-06-11 25 views
5

Estoy desarrollando un pequeño marco para acceder a la base de datos. Quiero agregar una característica que hace una consulta utilizando una expresión lambda. ¿Cómo hago esto?Cómo convertir la expresión lambda a sql?

public class TestModel 
{ 
    public int Id {get;set;} 
    public string Name {get;set;} 
} 

public class Repository<T> 
{ 
    // do something. 
} 

Por ejemplo:

var repo = new Repository<TestModel>(); 

var query = repo.AsQueryable().Where(x => x.Name == "test"); 
// This query must be like this: 
// SELECT * FROM testmodel WHERE name = 'test' 

var list = query.ToDataSet(); 
// When I call ToDataSet(), it will get the dataset after running the made query. 
+0

http://www.linqpad.net/ podría ayudarle. –

+1

Debe usar un marco O/RM que habilite LINQ sobre Expresiones, como LINQ to SQL o Entity Framework. – Steven

+1

¿Desea implementar un [proveedor de consultas] (http://msdn.microsoft.com/en-us/library/system.linq.iqueryprovider.aspx)? – phg

Respuesta

12

Seguir y crear un LINQ Provider (estoy seguro de que no desea hacer esto, de todos modos).

Es mucho trabajo, así que tal vez lo que desea es utilizar NHibernate o Entity Framework o algo por el estilo.

Si sus preguntas son bastante simples, tal vez usted no necesita un proveedor LINQ completo soplado. Eche un vistazo a Expression Trees (que son utilizados por los proveedores de LINQ).

Puede piratear algo como esto:

public static class QueryExtensions 
{ 
    public static IEnumerable<TSource> Where<TSource>(this Repo<TSource> source, Expression<Func<TSource, bool>> predicate) 
    { 
     // hacks all the way 
     dynamic operation = predicate.Body; 
     dynamic left = operation.Left; 
     dynamic right = operation.Right; 

     var ops = new Dictionary<ExpressionType, String>(); 
     ops.Add(ExpressionType.Equal, "="); 
     ops.Add(ExpressionType.GreaterThan, ">"); 
     // add all required operations here    

     // Instead of SELECT *, select all required fields, since you know the type 
     var q = String.Format("SELECT * FROM {0} WHERE {1} {2} {3}", typeof(TSource), left.Member.Name, ops[operation.NodeType], right.Value); 
     return source.RunQuery(q); 
    } 
} 
public class Repo<T> 
{ 
    internal IEnumerable<T> RunQuery(string query) 
    { 
     return new List<T>(); // run query here... 
    } 
} 
public class TestModel 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var repo = new Repo<TestModel>(); 
     var result = repo.Where(e => e.Name == "test"); 
     var result2 = repo.Where(e => e.Id > 200); 
    } 
} 

Por favor, no use esto como es. Este es solo un ejemplo rápido y sucio de cómo se pueden analizar los árboles de expresión para crear declaraciones SQL.

Por qué no utilizar Linq2Sql, NHibernate o ADO.NET Entity Framework ...

+0

Intenté usar el proveedor de linq. Lo hice explicado. Pero no funcionó. Hay demasiada clase. ¿No lo hago de una manera más simple? – sinanakyazici

+0

@sinanakyazici Agregué un ejemplo simple para que usted obtenga la idea – sloth

+0

@sinanakyazici Sí, crear un proveedor de linq es complejo. Es por eso que las personas no escriben las suyas propias si no tienen que hacerlo, sino que usan las existentes. – sloth

2

si quieres hacer cosas como

db.Employee 
.Where(e => e.Title == "Spectre") 
.Set(e => e.Title, "Commander") 
.Update(); 

o

db 
.Into(db.Employee) 
    .Value(e => e.FirstName, "John") 
    .Value(e => e.LastName, "Shepard") 
    .Value(e => e.Title,  "Spectre") 
    .Value(e => e.HireDate, () => Sql.CurrentTimestamp) 
.Insert(); 

o

db.Employee 
.Where(e => e.Title == "Spectre") 
.Delete(); 

Entonces mira esto, BLToolkit

0

Es posible que desee ver http://iqtoolkit.codeplex.com/ que es muy complejo y no le recomiendo que cree algo desde cero.

acabo de escribieron algo cercano a la respuesta de dkons voy a añadir que de todos modos. Simplemente usando una interfaz fluida nada más.

public class Query<T> where T : class 
{ 
    private Dictionary<string, string> _dictionary; 

    public Query() 
    { 
     _dictionary = new Dictionary<string, string>(); 
    } 

    public Query<T> Eq(Expression<Func<T, string>> property) 
    { 
     AddOperator("Eq", property.Name); 
     return this; 
    } 

    public Query<T> StartsWith(Expression<Func<T, string>> property) 
    { 
     AddOperator("Sw", property.Name); 
     return this; 
    } 

    public Query<T> Like(Expression<Func<T, string>> property) 
    { 
     AddOperator("Like", property.Name); 
     return this; 
    } 

    private void AddOperator(string opName, string prop) 
    { 
     _dictionary.Add(opName,prop); 
    } 

    public void Run(T t) 
    { 
     //Extract props of T by reflection and Build query 
    } 
} 

Digamos que tiene un modelo como

class Model 
    { 
     public string Surname{ get; set; } 
     public string Name{ get; set; } 
    } 

Usted puede utilizar esto como:

static void Main(string[] args) 
     { 

      Model m = new Model() {Name = "n", Surname = "s"}; 
      var q = new Query<Model>(); 
      q.Eq(x => x.Name).Like(x=>x.Surname).Run(m); 


     } 
+0

Property.Name siempre es nulo. Para extraerlo, deberá hacer lo siguiente: var expression = (MemberExpression) property.Body; string name = expression.Member.Name; –

+0

Y otra cosa es que no puedes usar dic piensa SI tienes "ME GUSTA" dos veces, ¿qué pasará entonces? –