Применение функции в выражениях LINQ - PullRequest
2 голосов
/ 31 мая 2011

Мы пытаемся найти обходной путь для проблемы, заключающейся в том, что Entity Framework не поддерживает нескалярные объекты. Мы используем определенное равенство, поэтому мы пытаемся создать выражение, которое для данного входа и функции из этого входа проверяет, выполняется ли это равенство.

    private static Expression<Func<TElement, bool>> UserEquals<TElement>(User user, Func<TElement, User> select)
    {
        var userequals = (Expression<Func<User, Boolean>>) (u => u.Source == user.Source && u.UserName == user.UserName);

        //return an Expression that receives an TElement, applies |select| and then passes that result to then `userequals` expression 
        // and uses it's result as return value.
    }

Я подозреваю, что это включает создание нового выражения, которое получает параметр, но я не могу понять, как применить функцию select к этому входу, а затем передать результат этого в выражение userequals.

Предполагаемое использование что-то вроде:

Context.Foo.Where(UserEquals(user, (f => f.User)).Single(f => f.Id == id);

Вместо:

Context.Foo.Single(f => f.Id == id && f.User.Source == user.Source && f.User.UserName == user.UserName);

В идеале мы хотели бы написать что-то вроде:

Context.Foo.Single(f => f.Id == id && f.User.Equals(user))
// or
Context.Foo.Single(f => f.Id == id && f.User == user)

Ответы [ 4 ]

3 голосов
/ 31 мая 2011

Итак, если я вас правильно понимаю, вы хотите сделать это:

public class Foo
{
    public int Id { get; set; }
    public User User { get; set; }
}

public class User
{
    public int Id { get; set; }
    public string Text { get; set; }
}

public static IQueryable<Foo> WhereUserEquals(this IQueryable<Foo> source, User user)
{
    // this is your implementation of the entity specific equality test
    return source.Where(x => x.User.Id == user.Id);
}

static void Main(string[] args)
{
    var list = new List<Foo> { new Foo { User = new User { Id = 1, Text = "User" } };

    var user = new User { Id = 1 };

    var q = list.AsQueryable().WhereUserEquals(user);

    foreach (var item in q)
    {
        Console.WriteLine(item.Text);
    }
}

Что позволит вам написать:

Context.Foo.WhereUserEquals(user).Single(f => f.Id == id);

Если у вас нет базового класса для доступа к свойству User типа Foo, вам нужно по одному такому расширению для каждого типа, однако это то, что вы могли бы довольно легко кодировать gen. Я не верю, что потребуется переписать дерево выражений.

1 голос
/ 31 мая 2011

Вы случайно ищете InvokeExpression ?

0 голосов
/ 01 июня 2011

Эта библиотека решает проблему: http://nuget.org/List/Packages/Microsoft.Linq.Translations

Подробнее об этом здесь: http://damieng.com/blog/2009/06/24/client-side-properties-and-any-remote-linq-provider

Я в значительной степени полагаюсь на это в работе.

0 голосов
/ 31 мая 2011

Может ли это сработать?

private static Expression<Func<TElement, bool>> UserEquals<TElement>(User user, Expression<Func<TElement, User>> select)
{
    return (Expression<Func<TElement, Boolean>>)(elt => select.Compile()(elt).Source == user.Source && select.Compile()(elt).UserName == user.UserName);
}

В настоящее время у вас есть несоответствие типов, поскольку select нигде не вызывается, и, таким образом, у вас нет TElement в качестве входных данных, но уже User.

Надеюсь, это поможет ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...