Как конвертировать лямбда-выражение в Sql?

Я разрабатываю небольшую структуру для доступа к базе данных. Я хочу добавить функцию, которая делает запрос с использованием лямбда-выражения. Как мне это сделать?

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

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

Например:

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.

3 ответа

Продолжайте и создайте LINQ Provider (я уверен, что вы все равно не хотите этого делать).

Это много работы, так что, возможно, вы просто хотите использовать NHibernate или Entity Framework или что-то в этом роде.

Если ваши запросы довольно просты, возможно, вам не нужен полноценный поставщик LINQ. Взгляните на деревья выражений (которые используются поставщиками LINQ).

Вы можете взломать что-то вроде этого:

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

Пожалуйста, не используйте это как есть. Это простой и грязный пример того, как деревья выражений могут быть проанализированы для создания операторов SQL.

Почему бы просто не использовать Linq2Sql, NHibernate или EntityFramework...

Если вы хотите делать такие вещи, как

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

или же

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

или же

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

Тогда проверьте это, BLToolkit

Возможно, вы захотите взглянуть на http://iqtoolkit.codeplex.com/ Это очень сложно, и я не рекомендую вам создавать что-то с нуля.

Я просто написал что-то близкое к ответу Дконса, я все равно добавлю его. Просто используя свободный интерфейс ничего больше.

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   
    }
}

Допустим, у вас есть модель, как

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

Вы можете использовать это как:

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


        }
Другие вопросы по тегам