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:prawie 16 lat
  • Ostatnio:4 miesiące
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:około 5 godzin
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:około 16 godzin
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:około 5 godzin
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.

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)