Jak zamienic string na select w LINQ?

0

Witam wszystkich,

pytanie brzmi jak (dynamicznie) zamienic "dowolny" string na to co LINQ ma w select.
Dla wyjasnienia przykladzik:

 
string s = "((x.BMK_SU + x.BMK_AEP) * 1.5 + 10)";
//Powyzszy string jest wczesniej sprawdzony i jest poprawny, znaczy bedzie przetworzony i zwroci wynik
//o ile skumam jak go "zasymilowac" z zapytaniem :D

var wtf = (from x in BdeDb.Kontext.TbMachine
                      where blabla (np: x.Machine == sam.Machine)
                      select *@s); 

//* za @s chccialbym wstawiac stringa i otrzymac:

var okidoki = (from x in BdeDb.Kontext.TbMachine
                    where blabla (np: x.Machine == sam.Machine)
                    select ((x.BMK_SU + x.BMK_AEP) * 1.5 + 10);

Cala reszta, oprocz select jest stala - select "dynamiczny". Za wskazowki expertow LINQ bylbym wdzieczny, bo chyba zle google uzywam i nie znajduje odp. ;)

1

Nie wygląda ten string na sprawdzony i poprawny, a przynajmniej ten jeden nawias zamykający więcej niż otwierający wygląda podejrzanie :P.

W każdym razie prosto się nie da, w sumie to prawdopodobnie próbujesz zrobić coś bardzo na około.
Problem polega na tym że kod (to wyrażenie LINQ) jest kompilowane na etapie (logiczne ;) kompiliacji, a string jest znany dopiero w momencie wykonywania kodu (czyli nie możesz podmienić skompilowanego kodu za pomocą stringa znanego dopiero w czasie wykonania).

Nie-prosto się da, na przykład tak (ale nie polecam):

using (CSharpCodeProvider foo = new CSharpCodeProvider()) {
    string s = "(sam.BMK_SU + sam.BMK_AEP) * 1.5 + 10";
    var assembly = foo.CompileAssemblyFromSource(
        new System.CodeDom.Compiler.CompilerParameters() { 
            GenerateInMemory = true
        },
        @"public class DynamicClass {
            // to /nadal/ nie zadziała, musisz jakoś przekazać BdeDb albo Kontext.
            // najlepiej w parametrze, o ile nie jest statyczna
            public string Execute() {
                return (from x in BdeDb.Kontext.TbMachine
                    where blabla
                    select " + s + @"); 
            }
        }"
    );

    var type = assembly.CompiledAssembly.GetType("DynamicClass");
    var instance = Activator.CreateInstance(type);
    var output = type.GetMethod("Execute").Invoke(instance, new object[0]);
}

Tutaj cały kod jest stringiem, kompilowanym razem z podstawionym s w momencie wykonywania kodu.

Poczytaj na przykład o klasie Expression<T>, może o coś takiego Ci chodzi. Albo napisz co chcesz osiągnąć.

0

Nie zrobisz tego w ten sposób, zaletą Linq jest to, że jest silnie typowany, pozbawiony 'magic stringów' i przy kompilacji wywala wszelakie błędy.
Zainteresuje się dodatkiem dynamic linq (http://dynamiclinq.codeplex.com/) może w jakiś sposób Ci pomoże.
Powiem Ci jednak szczerze - jeżeli zadajesz takie pytanie, to z dużym prawdopodob. coś źle zaplanowałeś i istnieje prostsze rozwiązanie Twojego problemu.

0

Da się. Trzeba by było parsować stringa i na tej podstawie generować dynamicznie zapytanie.
Ale to będzie dużo roboty.

1

Można zrobić from ... select x, a potem już poza linq zrobić wypełnianie stringa otrzymanymi danymi i na koniec wykonywać zawarte w tymże stringu działania (onp).

0

Możesz użyć http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
lub spróbować przerobić tekst na ExpressionTree. W zasadzie wszystkie zapytania LINQ konwertowane są na ExpressionTree.

0

W sumie jednak (z wewnetrznymi oporami - bo nie uwazam zeby to bylo jakies duze lepsze rozwiazanie niz wrzucenie calej formulki jako string do Math-parsera) skorzyslalem dzis z dynamicQuery:

 
          //test         
         IQueryable<Data1> baseQuery = (from c in ctx.Kontext.Data1 select c);
         IQueryable <Data1> whereClauseQuery = whereMachine( baseQuery, machine );

         List<Data1> sapListe = whereClauseQuery.ToList();
         
         //testowe
         string s = "((BMK_SU + BMK_AEP) * 1.5 + 10)+)";
         string s1 = "(BMK_SU + BMK_AEP) * 1.5 + 10";
         //def typ direct? 
         s1 = "1.0*(" + s1 + ")";

         IQueryable<Data2> samQuery = (from c in ctx.Kontext.Data2 select c);
         var rs = selectStatement( samQuery, s1, data2var );

        // double l1 = rs.SingleOrDefault();

         return sapWorkerExtensionsObject;
      }

      private dynamic whereMaschine( dynamic query, int machine )
      {
         string whereMaschine = "it.Machine == " + machine.ToString();
         var returnQuery = (IQueryable<object>)query;
         //test
         var query2 = DynamicQueryable.Where( query, whereMachine );
         
       return query2;
      }

      private dynamic selectStatement( dynamic query, string expression, Data2 data2var )
      {
         
         int machine = data2var.Machine;
         string au = data2var .Au;
         string ar = data2var.Ar;
                 
          //test where string
         string whereMaschine = "it.Machine == " + machine.ToString() + " && it.Au == " + "\""+ au + "\"";// + " && it.Ar == " + ar;
         var q3 = DynamicQueryable.Where( query, whereMachine );
         
         //test select string
         q3 = DynamicQueryable.Select( q3, expression );
         return q3;
      }

Obie metody DynamicQueryable.Select/DynamicQueryable.Where pozwalaja na (m.in) wrzucenie dowolnego stringa i zwracaja query. Dzialac dziala. O bledach w nazwie kolumn czy jakichkolwiek bledach skladni dowiemy sie naturalnie dopiero w czasie pracy programu.
Ale moze ktos kiedys bedzie potrzebowal.
Pozdrawiam.

0
      private dynamic whereMaschine( dynamic query, int machine )
      {
         string whereMaschine = "it.Machine == " + machine.ToString();
         var returnQuery = (IQueryable<object>)query;
         //test
         var query2 = DynamicQueryable.Where( query, whereMachine );
 
       return query2;
      }

Do tego nie trzeba dynamic.

var query = ...;
string m = machine.ToString();
var query2 = query.Where(it => it == m);
0

a o tym słyszałeś ?

http://dynamiclinq.codeplex.com

Musisz być pewien ze to co wygenerujesz w stringu na 100% bedzie poprawnym Zapytaniem linq.

1 użytkowników online, w tym zalogowanych: 0, gości: 1