Как параметризовать запрос в Entity Framework?

Я новичок в ЭФ. У меня есть таблица со списком проектов. Я нашел запрос в своем программном обеспечении, который находит все проекты.

public Project[] FindAll()
{
    var projects = new List<Project>();
    using (var db = new ProjetDbConext())
    {
        var qProjects = from project in db.ProjectSet
            where project.CreateDateTime != null
            select project;
        projects = qProjects.ToList();
    }
    return projects.ToArray();
}

Кажется, это нормально, но я не уверен, как это параметризовать. Мне это нужно, потому что я реализую функцию поиска, пытаясь повторно использовать некоторую логику запроса из EF.

Для этого требуется список кортежей. Каждый кортеж в основном имеет атрибут и список условий поиска.

например. Кортеж(Имя, {Прасант, Билл}; Кортеж(Фамилия, {Нилакандан, Гейтс};

Это означает, что мне нужно написать запрос выбора, в котором я ищу проекты, где FirstName — это Prasaanth или Bill. Если в списке только один термин.

например. Tuple(Company, {Microsoft}; тогда мне нужно искать только одно условие where в моем запросе.

 public Project[] LoadSearchProjects(List<System.Tuple<string, List<string>>> searchTerms)
        {
            var projects = new List<Project>();

            using (var db = new ProjetDbConext())
            {
                foreach (System.Tuple<string, List<string>> pair in searchTerms)
                {

                    string attribute = pair.Item1;
                    List<string> terms = pair.Item2;

                      /// logic here
                 }  
            }
            return projects.ToArray();

        }

Я всегда могу написать условие if, где я делаю:

if(attribute.equals("FirstName"){

 // query project.FirstName in the where conditon 


}

Но у меня слишком много атрибутов для поиска.

Я знаю способ ADO.NET сделать это:

 mycommands = new SqlCommand(" select projects from from Persons where '"+attibute+"' =  some search terms ... 

Я не знаю, как сделать что-то подобное в моем запросе EF.

1) Есть ли способ, которым EF позволяет мне выполнять поиск по динамическим атрибутам? или параметризовать с помощью '"+attribute+"' ??

2) Есть ли лучшая структура данных, которую я мог бы использовать для упрощения своей структуры вместо использования List<Tuple<string, List<string>>?

3) Мне рекомендовали использовать сторонний LINQKit или динамический linq, но я не уверен, как интегрировать это в запросы EF.

Мои извинения, если многое из этого звучит как код студента. Пожалуйста, дайте мне знать, если потребуется дополнительная информация.

С уважением, Прасаант

ОБНОВЛЕНИЕ: Метод работы согласно ответу Андрея. Мой вопрос здесь в том, что это не работает, если какая-либо конкретная запись в моей базе данных говорит, что имя равно Null.

 private static Expression<Func<TEntity, bool>> BuildStringFilter<TEntity, TProp>(
            Tuple<string, List<string>> filter)
        {
          // entity is the Project table
            var entity = Expression.Parameter(typeof (TEntity));
            var prop = Expression.Property(entity, filter.Item1);

            //check if contains returns true

            var body = filter.Item2
                .Select(v => Expression.Equal(Expression.Call(prop,
                    typeof (String).GetMethod("Contains"),
                    new Expression[] { Expression.Constant(v) }), Expression.Constant(true)))
                .Aggregate(Expression.Or);



            var result = (Expression<Func<TEntity, bool>>) Expression.Lambda(body, entity);
            return result;
        }

В любом случае я могу изменить выражение, чтобы метод Contains:

prop, typeof (String).GetMethod("Содержит"), new Expression[] { Expression.Constant(v)

работает, если значение атрибута (prop) равно null?


person Prasaanth Neelakandan    schedule 17.07.2015    source источник
comment
Взгляните на библиотеку System.Linq.Dynamic.   -  person Sam FarajpourGhamari    schedule 17.07.2015


Ответы (2)


Вы можете построить выражение фильтра, используя сниппет:

public static Expression<Func<TEntity, bool>> BuildFilter<TEntity, TProp>(
    KeyValuePair<string, IEnumerable<TProp>> filter)
{
    var entity = Expression.Parameter(typeof(TEntity));
    var prop = Expression.Property(entity, filter.Key);

    var body = filter.Value
        .Select(v => Expression.Equal(prop, Expression.Constant(v)))
        .Aggregate((curr, next) => Expression.Or(curr, next));

    var result = (Expression<Func<TEntity, bool>>)Expression.Lambda(body, entity);
    return result;
}

И назовите это так:

var filter = new KeyValuePair<string, IEnumerable<string>> (
    "FirstName",
    new [] {"Alice", "Bob"}
);

var predicate = BuildFilter<Item, string>(filter);
var result = ctx.Items.Where(predicate);

Также см. Как использовать деревья выражений. для построения динамических запросов.

person at least 3 and no more than 30    schedule 17.07.2015
comment
привет.. является ли ctx экземпляром ProjetDbContext()?? Когда я вызываю это, он не может найти символ Item? - person Prasaanth Neelakandan; 20.07.2015
comment
Элемент - это то, что в вызове BuildFilter? - person Prasaanth Neelakandan; 20.07.2015
comment
Ctx — это экземпляр DbContext, а Items — это DbSet. Вы можете использовать db и ProjectSet вместо него в вашем случае. - person at least 3 and no more than 30; 21.07.2015
comment
это то, что я догадался и попробовал. но ProjectSet/DbSet, похоже, не имеет расширения where. есть ли какой-либо код библиотеки или расширения, который мне не хватает? - person Prasaanth Neelakandan; 21.07.2015
comment
Расширение Where находится в пространстве имен System.Linq из сборки System.Core.dll. - person at least 3 and no more than 30; 21.07.2015
comment
в любом случае, сэр, я думаю, что эта структура данных не будет работать. это просто пара значений ключа для одного атрибута и условия поиска. Мне нужен список таких пар ключ-значение. - person Prasaanth Neelakandan; 21.07.2015
comment
Почему это не работает? Вы получили какую-либо ошибку? Это всего лишь пример кода, который показывает вам правильное направление. При необходимости его можно легко расширить. - person at least 3 and no more than 30; 21.07.2015
comment
ctx, то есть ProjectDbcontext не имеет свойства Items :( - person Prasaanth Neelakandan; 27.07.2015
comment
наконец, старший человек здесь смог помочь мне адаптировать ваш ответ .. большое спасибо .. ура \ m / теперь я пытаюсь изменить его, чтобы делать Like вместо равных - person Prasaanth Neelakandan; 28.07.2015
comment
может быть у вас есть идея сделать «Содержит» или «Мне нравится» вместо Expression.Equal(prop, Expression.Constant(v))) ?? - person Prasaanth Neelakandan; 28.07.2015
comment
var body = filter.Item2 .Select(v => Expression.Equal(Expression.Call(prop, typeof (String).GetMethod(Contains), new Expression[] { Expression.Constant(v) }), Expression.Constant( правда))) .Агрегат(Выражение.Или); - person Prasaanth Neelakandan; 28.07.2015
comment
Привет, Андрей, есть идеи, как я могу заставить это работать, если значение в моей БД равно NULL - person Prasaanth Neelakandan; 03.08.2015
comment
Используйте тот же метод Expression.Constant(), см.: msdn. microsoft.com/en-us/library/bb338689%28v=vs.110%29.aspx. - person at least 3 and no more than 30; 04.08.2015
comment
Привет Андрей, я это понял. все еще не мог понять, как объединить это значение с null . Я пробовал некоторые вещи, используя Expression.Coalesce . Идея здесь состоит в том, чтобы гарантировать, что свойство может быть нулевым, т.е. prop. См. редактирование. Если есть идеи по этому поводу, пожалуйста, дайте мне знать. - person Prasaanth Neelakandan; 02.09.2015

Я плююсь здесь, но я думаю, что что-то вроде этого было бы проще:

public Project[] Find(Expression<Func<Project, bool> filter = null)
{    
    using (var db = new ProjetDbConext())
    {
        var query = db.ProjectSet.Where(p => p.CreateDateTime != null);

        if(filter != null)
            query = query.Where(filter);

       return query.ToArray();
    }
}

Используйте это как:

var projects = repo.Find(p => p.id > 100);
person Mister Epic    schedule 17.07.2015
comment
Это не позволяет мне предоставлять атрибут для поиска на лету. например, идентификатор в случае примера, который вы предоставили - person Prasaanth Neelakandan; 21.07.2015
comment
что ты имеешь в виду под словом "на лету"? он позволяет искать проекты на основе произвольных предикатов. - person sara; 21.03.2016