Jak zamienic string na select w LINQ?

Jak zamienic string na select w LINQ?
M6
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 9 lat
  • Postów:2
0

Witam wszystkich,

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

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

edytowany 3x, ostatnio: miro610
msm
Administrator
  • Rejestracja:około 16 lat
  • Ostatnio:5 miesięcy
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):

Kopiuj
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ąć.

edytowany 10x, ostatnio: msm
M6
Dzieki za podpowiedz, sprawdze, moze jakas lambde wyczaruje ze stringa i wrzuce w .Select() czy cos, o ile bedzie szybko :D
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.

M6
Szczerze to mam inne rozwiazania. I wowczas to cale te obliczenia dokonywane w select w ogóle nie stanowia problemu. Tak po prawdzie to ten string zawiera tylko kilka zmiennych, ktore wczesniej sobie pobieram z bazy, podmieniam w stringu - wrzucam stringa w parser i otrzymuje wynik(double). Ale.. mam pewnego expert-oszoloma w projekcie, ktory uparl sie na rozwiazanie w LINQ... Parser bee, SQL serwer niech liczy... Chcialem to na szybko i bezbolesnie zakodowac - jesli byloby to przyslowiowe pare minut. A jak nie - to skorzystam z tego co mam, a oszolom niech sobie narzeka :D
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:minuta
0

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

ŁF
Moderator
  • Rejestracja:ponad 22 lata
  • Ostatnio:2 dni
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).


M6
:D Hehe - to jak pisalem wczesniej nie jest problemem - wypelnianie danymi i wrzucenie stringa w uzywany MathParser ;)
Azarien
to dlaczego tego nie zrobisz?
M6
Siemka, wczoraj mnie wywialo na jakies kolejne zabranie (blee) - jesli chodzi o parser to to jest moje obecne rozwiazanie - podmieniam w stringu zmienne na liczby i tego stringa wrzucam w parser - ale mam tu takiego mistrza projektu, ktoremu sie to nie podoba. LINQ jest jego "wymarzonym" rozwiazaniem. Bo i wzor jego zdaniem dodtkowo sprawdzi i, i ... w ogole zewnetrzne komponenty "sa bee" (nawet takie malutkie klasy jak ten parser ;)) W ogole kolo jest fanatykiem sql i jakby mogl to by przeniosl cala logike do serwera SQL. :D
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.

M6
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 9 lat
  • Postów:2
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:

Kopiuj
 
          //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.

edytowany 1x, ostatnio: miro610
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:minuta
0
Kopiuj
      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.

Kopiuj
var query = ...;
string m = machine.ToString();
var query2 = query.Where(it => it == m);
M6
Slusznie i tak na to patrzac teraz przyznaje, ze jest tam pare niepotrzebnych linijek w tym przykladzie. Wczesniej nie mialem portrzeby korzystac DynamicQueryable. Po prostu testowalem. Sorki, ze nie posprzatane ;)
L3
  • Rejestracja:prawie 14 lat
  • Ostatnio:około 10 lat
  • Postów:106
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.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.