2013-07-15 6 views
0

В моем текущем проекте в репозитории используется EntityFramework со многими таблицами как News. Итак, каждый раз у нас есть новый входной функционал, мы создаем соответствующую базу данных, генерируем edmx, создаем новый метод в репозитории. Пример: db.News.Where (c => c.Name == 'myNews'); db.Arts.Where (c => c.ArticleName == 'myArticle');Динамический параметр выражения лямбда

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

Я создал этот код с помощью Generic. Так что это образец кода, идеал в порядке, я могу создать стандартный метод, сначала взяв propertyName и строковый поиск. Оно работает.

Декларация

public class SampleClass 
{ 
    public string SomeField = "Test"; 
} 

public class ConfSampleClass2 
{ 
    public Type Type { get; set; } 
} 

Вызов:

IQueryable result = GetCompaniesA<SampleClass2>("Name", "alpine"); 

Метод:

public IQueryable GetCompaniesA<T>(string propertyName, string search) 
{ 
try 
{     
IQueryable<T> results = null; 
SampleClass2 sc2 = new SampleClass2(); 
List<SampleClass2> listSc2 = new List<SampleClass2>(); 
listSc2.Add(new SampleClass2() { Name = "alpine" }); 
listSc2.Add(new SampleClass2() { Name = "Statue" }); 
listSc2.Add(new SampleClass2() { Name = "Gateau" }); 

//listSc2.Where(c => c.Name == "alpine"); 
IQueryable<SampleClass2> queryableData = listSc2.AsQueryable<SampleClass2>(); 

// Compose the expression tree that represents the parameter to the predicate. 
ParameterExpression pe = Expression.Parameter(typeof(T),typeof(T).Name); 
Expression member = Expression.Property(pe, typeof(T).GetProperty(propertyName)); 
Expression left = Expression.Call(member, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes)); 
Expression right = Expression.Constant(search); 
Expression e1 = Expression.Equal(left, right);     
MethodCallExpression whereCallExpression = 
Expression.Call(
typeof(Queryable), 
"Where", 
new Type[] { queryableData.ElementType }, 
queryableData.Expression, 
Expression.Lambda<Func<T, bool>>(e1, new ParameterExpression[] { pe }));     
return queryableData.Provider.CreateQuery(whereCallExpression); 
} 
catch (Exception ex) 
{ 
throw ex; 
} 
} 

Но я хотел бы пойти дальше избегать использования общего, но с использованием динамического, чтобы избежать название связи. Так что я изменить метод, чтобы получить этот один:

Вызов:

Console.WriteLine(GetCompaniesDynamic(new ConfSampleClass2(){ Type=typeof(SampleClass2) },"Name", "alpine")); 

Метод:

public IQueryable GetCompaniesDynamic(dynamic dynamicObj, string propertyName, string search) 
{ 
try 
{ 
    IQueryable results = null; 
    SampleClass2 sc2 = new SampleClass2(); 
    List<SampleClass2> listSc2 = new List<SampleClass2>(); 
    listSc2.Add(new SampleClass2() { Name = "alpine" }); 
    listSc2.Add(new SampleClass2() { Name = "Statue" }); 
    listSc2.Add(new SampleClass2() { Name = "Gateau" }); 
    IQueryable<SampleClass2> queryableData = listSc2.AsQueryable<SampleClass2>(); 

    ParameterExpression pe = Expression.Parameter(dynamicObj.Type, dynamicObj.Type.Name); 
    Expression member = Expression.Property(pe, dynamicObj.Type.GetProperty(propertyName)); 
    Expression left = Expression.Call(member, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes)); 
    Expression right = Expression.Constant(search); 
    Expression e1 = Expression.Equal(left, right); 

    //the issue appears on this line ParameterExpression of type //'EntityFrameworkGeolocationExpression.SampleClass2' cannot be used for delegate parameter //of type 'System.Object', I can't compile if I replace Object by Dynamic. 
    MethodCallExpression whereCallExpression = 
     Expression.Call(
      typeof(Queryable), 
      "Where", 
      new Type[] { queryableData.ElementType }, 
      queryableData.Expression,       
      Expression.Lambda<Func<Object, bool>>(e1, new ParameterExpression[] { pe })); 
    return results = queryableData.Provider.CreateQuery(whereCallExpression);     
} 
catch (Exception ex) 
{ 
    throw ex; 
} 
} 

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

Помогите мне пойти дальше?

С наилучшими пожеланиями, Александр

+2

Возможно, вам нужно просто скопировать код EF напрямую: 'db.News.Where (c => c.Name == 'myNews')'. Почему это не работает для вас? – usr

+0

Спасибо за ваше предложение НО, я хотел бы разработать свой код, у меня нет только новостей и статей, у меня теперь около 30 таблиц, поэтому я ищу универсальное решение, позволяющее выполнить общий вызов. Это позволяет также абстрагироваться от дальнейшего обращения к репозиторию. – user2416437

+0

@ user2416437 - Абстрактное выражение, чтобы вы могли использовать строки или 'dynamic' вместо фактических свойств - плохая идея.Вы теряете безопасность типа, вы теряете ошибки компиляции, когда ваш объект меняется, и вы теряете intellisense. Это плохая идея. – Bobson

ответ

0

Как я уже говорил в моем комментарии, я думаю, что это плохая идея. Тем не менее, существует (непроверенный) тривиально простой способ реализовать поведение, которое, как я думаю, вы ищете.

public IQueryable GetCompaniesDynamic(string table, string property, string search) 
{ 
    using (var context = new DBContext()) 
    { 
     return context.Database.SqlQuery("SELECT * FROM dbo." + table + " WHERE " 
             + property + " = '" + search + "'"); 
    } 
} 

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

var companies = GetCompaniesDynamic("News", "Name", "myNews"); 

Обратите внимание, что это оставляет вас уязвимыми для SQL инъекций, если вы не дезинфицировать свои входные, орфографические ошибки и опечатки, которые вы никогда не поймает, пока приложение взрывается во время выполнения и просто забывает, какие поля называются. Я не знаю, почему вы используете инфраструктуру сущности, когда явно не хотите каких-либо функций, которые она предоставляет. Но удачи.

Смежные вопросы