Expression Trees - 2. daļa

Turpinot tēmu par izteiksmju kokiem, pirmā daļā apskatīju nelielu ievadu šajā tehnoloģijā un apskatīju pāris pamatprincipus, kas tad īsti ir izteiksmju koki.

No pirmā acu uzmetiena izskatās, ka izteiksmju koki paredzēti tikai vaicājuma izteiksmes (lambda izteiksme) pārvēršanai datos, lai no tiem varētu tranformēt pieprasījumu kādā pavisam citā tehnoloģijā (piemēram, labmda izteiksmes -> SQL vaicājums). Tomēr nedaudz apskatot tehnoloģiju tuvāk var ieraudzīt nelielu potenciālu vaicājumu vai filtrācijas mehānisma izveidei tieši izpildes laikā (runtime).

Noteikti, ka sistēmās redzēti šāda veida ekrāni:

 

 

Šāda veida izteiksmes var kontruēt arī ar izteiksmju koku palīdzību. Pirmo betu mēģināsim uzkontruēt šoreiz.

Pirmais, kas mums ir nepieciešams ir datu avots kuru vēlamies filtrēt. Šim nolūkam var izmantot gan objektu kolekcijas (IEnumerable<T> interfeiss), gan arī datus no kāda cita datu avota, kas realizē IQueryable<T> interfeisu.

Kā datu avotu izmantosim SQL datu bāzi ar ļoti vienkāršu modeli, kas satur fiktīvu klientu datus:

 

 

Pēc tam kad datu avots uz izveidots, varam ķerties pie filtrācijas metodes izveides. Paraksts metodei, kas veiks datu avota filtrāciju būs šāds:

 

public T[] FilterSource<T>(IEnumerable<T> list)

 

Metode saņems sarakstu ar elementiem, kas nāk no datu avots (IEnumerable<T> interfeiss, par cik IQueryable<T> mantojas no šī interfeisa, tad objektorientētā programmēšana mums nodrošina arī pieeju IQueryable<T> interfeisam šādā metodes parakstā).

 

Iesākumā jāizdomā kāds būs vaicājuma koks, kas ir jāģenerē (pirmajā betā diemžēl tiek apskatītas tikai vienlīmeņa vaicājumi bez sarežģītākām izteiksmēm).

Konstruējamais izteiksmes koks ir šāds:

  • iesākumā mums visa izteiksme ir jāparametrizē jeb jānodefiē, kas ir nākošais parametrs izteiksme un kam tiks piemērots tālākās filtrācijas izteiksmes. Šim nolūkam izmantosim Expression.Parameter;
  • pēc tam ir jāizveido izteiksmes ķermenis (expression body), kas varbūt dažāda veida bināras izteiksmes (=, !=, >, <, utt.). Šim nolūkam izmantosim, piemēram, Expression.Equal metodi;
  • lai sekmīgi izveidotu izteiksmes ķermeni, binārajai operācijai ir nepieciešama labās un kreisās puses izteiksmes;
  • kreisā puse ir ienākošā objekta īpašības izteiksme (izteiksme, kas izsauc objekta īpašību - property). Šim nolūkam izmantosim Expression.Property metodi;
  • labā puse parasti ir konstante, ko ievada lietotājs filtrācijas veidošanas ekrānā (pagaidām, šī programmas versija piedāvā tikai filtrāciju pēc iepriekš ievadītas konstantes, vairāk advancētus topikus domājams aprakstīt nākamajos rakstos par izteiksmju kokiem). Šim nolūkam izmantosim Expression.Constant metodi;
  • pēc tam izveidoto izteikmsi varam iekļaut lambda izteiksmē ar Expression.Lambda metodes palīdzību;

 

 

Jāņem vērā ar vēl daži konvertācijas un tipu nesakritības problēmas, bet tās visas iznesām ārā uz palīdzības metodēm atvieglojot pašu filtrācijas izteiksmes veidošanas kodu. Tātad kopējās kods izskatās šāds:

 

var incoming = Expression.Parameter(typeof (T), "c");
var propertyExpression = Expression.Property(incoming, property);
var propertyInfo = (PropertyInfo)propertyExpression.Member;
var pType = propertyInfo.PropertyType;
var constant = CreateConstantExpr(exprValue, pType);

Expression expr = null;

switch (op)
{
case "=":
expr = Expression.Equal(propertyExpression, constant);
break;
case "LIKE":
// special case - LIKE operation (we need to invoke `Contains(string)' method on target property if it's type of string)
if (pType == typeof(string))
{
expr = Expression.Call(propertyExpression, "Contains", null, constant);
}
else
{
expr = Expression.Equal(propertyExpression, constant);
}
break;
case "!=":
expr = Expression.NotEqual(propertyExpression, constant);
break;
case ">":
expr = Expression.GreaterThan(propertyExpression, constant);
break;
case ">=":
expr = Expression.GreaterThanOrEqual(propertyExpression, constant);
break;
case "<":
expr = Expression.LessThan(propertyExpression, constant);
break;
case "<=":
expr = Expression.LessThanOrEqual(propertyExpression, constant);
break;
}

var lambda = Expression.Lambda(expr, incoming);

 

Tātad koda loģika ir šāda:

  1. izveidojam ienākošā parametra izteiksmi;
  2. izveidojam īpašības piekļūšanas izteiksmi;
  3. izveidojam konstantes izteiksmi atkarībā no mērķa objekta īpašības datu tipa;
  4. pēc izvēlētā operatora konstruējam pirmā līmeņa izteiksmes ķermeni;
  5. izveidoto izteiksmi ietveram labmda izteikmsē, kuru parametrizējam ar ienākošo mērķa objektu;

 

 

Tālāk jaunizveidotā lambda izteiksme būtu jāpielieto datu avota datu filtrācijai. Ja aplūkojam IEnumerable<T> un IQueryable<T> interfeisu Where() metodes, tad ieraugām nelielu atšķirību:

 

public static System.Linq.IQueryable<TSource> Where<TSource>(this System.Linq.IQueryable<TSource> source, System.Linq.Expressions.Expression<Func<TSource,bool>> predicate)
public static System.Collections.Generic.IEnumerable<TSource> Where<TSource>(this System.Collections.Generic.IEnumerable<TSource> source, System.Func<TSource,bool> predicate)

 

Atšķirība ir tāda, ka IEnumerable<T> interfeiss sagaida jau sagatavotu Func<TSource, bool> objektu (delegātu), kuru pielieto katram no kolekcijas elementiem, lai veiktu nepieciešamo filtrāciju datu kopai.

Turpretīm, IQueryable<T> interfeiss sagaida Expression<Func<TSource, bool>> objektu, kas ir izteiksmes objekts, kuru vēlāk izmanto System.Linq.IQueryProvider Provider { get; } objekts, lai konvertētu funkcijas delegātu uz izteiksmes koku, kuru izmanto nepieciešamo tranformāciju veikšanai.

Lai gan pēc metodes paraksta ir redzama atšķirība, tomēr LINQ to SQL un Entity Framework (šie ir datu avotu, kas tiek pielietoti aplikācijā) dzinēji pielieto arī norādīto Func delegātu, ja ar datu avotu tiek strādāts kā ar IEnumerable<T> interfeisu, kas patīkami saīsina kodu.

Tātad, lai iegūtu Func<TSource, bool> delegātu no lambda izteiksmes, nepieciešams to vienkārši nokompilēt konvertējot to uz delegātu. Ģenerētās lambda izteikmes pielietošana datu avota filtrācijai ir sekojoša:

 

var func = (Expression<Func<T, bool>>)lambda;
return list.Where(func.Compile()).ToArray();

 

Tas arī viss pagaidām.

Zemāk ir redzami pāris ekrāna šāviņi no programmas darbības:

 

 

 

Šajā programmas versijā ir zināmi jau pāris mīnusi. To realizācija ir paredzēta nākamjās versijās:

  1. Viena līmeņa hierarhija: izteiksmes pagaidām nodrošina tikai viena līmeņa izteiksmes, piemēram, nav iespējas veidot izteiksmes: kur `vārds' LIKE 'Jān%' UN `dzimšanas-datums' >= 1974-04-23
  2. Mērķa datu avota objektiem ir pieejams tikai pirmā līmeņa īpašības, t.i., nevar veidot pagaidām vaicājumus kā, piemēram, `klients'.`adrese'.`iela' = 'Brīvības'
  3. Pagaidām iespējama tikai salīdzināšana ar iepriekš ievadītu konstanti, piemēram, nav iespējams veidot vaicājumu `klients'.`vārds' != `klients'.`uzvārds'

 

 

 

Cerams, ka šis raksts deva lielāku ieskatu izteiksmju kokos un reālāku pielietojumu informācijas sistēmās. Jāatzimē, protams, ka pirmā versija programmai nav diezko bagāta ar iespējām, bet tas ir tikai laika jautājums :) Nākāmajā rakstā mēģināsim norealizēt iztrūkstošo funckionalitāti un apskatīsim vēl advancētākus topikus ar vēl reālāku ikdienas pielietojumu biznesa informācijas sistēmās.

 

Cerams, ka noderēs!

Published Sunday, October 12, 2008 10:21 PM by valdis.iljuconoks

Comments

# re: Expression Trees - 2. daļa

Решебники для школьников

Wednesday, March 09, 2011 1:24 PM by решебники

# re: Expression Trees - 2. daļa

This is perfect that people can get the <a href="http://bestfinance-blog.com">loan</a> and that opens up completely new possibilities.

Saturday, May 28, 2011 4:02 AM by Bernard31Concepcion

# re: Expression Trees - 2. daļa

People would like to buy term paper and buy essays about this good post, at the research paper writing service.

Tuesday, May 31, 2011 9:36 PM by buy an essay

# re: Expression Trees - 2. daļa

Are you going to buy a term paper? Therefore, you have to know that prices for academic papers are not high now and it is a right time to get good papers.

Thursday, June 02, 2011 6:46 PM by term papers online

# re: Expression Trees - 2. daļa

I never strive to complete by my own just because I am not a specialist. Thus, I find essay writing service and feel no difficulties with my acacemic papers writing tasks.

Thursday, June 02, 2011 11:33 PM by do my essay

# re: Expression Trees - 2. daļa

The day before yesterday I used to be disappointed because of my critical essays performing assignment. But, my friend offered to find distinguished essay writing service. Hence, I did it and reached A+.  

Monday, June 06, 2011 5:22 AM by essay writing service

# re: Expression Trees - 2. daļa

Every college student knows that to buy a term paper at essays writing services would save free time. Thence I will advice to purchase the term papers rather than to compose that by their own.  

Monday, June 06, 2011 10:06 AM by essay papers

# re: Expression Trees - 2. daļa

Do not even attempt to complete your essays when you do not have writing skills. To ask: " write my essays " supposes to be great way under such circumstances.  

Tuesday, June 07, 2011 11:41 PM by write my papers

# re: Expression Trees - 2. daļa

You need to waste lots of time to write your research papers, nevertheless a distinguished custom research papers service would do it more faster. What for complete academic papers? Wtiting firms will do it for you.

Wednesday, June 08, 2011 3:26 AM by research papers for sale

# re: Expression Trees - 2. daļa

Asking your friends to submit boolmarks? Nonetheless, no one can support you much better than social bookmarking submission services.

Thursday, June 09, 2011 6:59 PM by social bookmarking services

# re: Expression Trees - 2. daļa

Wondering for the best again and will be back to see some more...

Saturday, September 17, 2011 1:01 PM by term papers

# re: Expression Trees - 2. daļa

Good blog i like it thanks, and keep going

Tuesday, September 20, 2011 8:34 AM by Resume Writing

# re: Expression Trees - 2. daļa

Great post, I always follow your blog since it is full of persuasive information about various things

Tuesday, November 01, 2011 8:46 AM by Resume Writers

# Resume Writing Services

Really I am pleased about the effort you made to share the knowledge. The topic here I found was really efficient to the topic which I was researching for a long time.

Monday, November 21, 2011 6:33 AM by CV Writing Services

# nsmyIJFqPTbtyer

xRh617 I really enjoy the post.Really thank you!

Thursday, March 22, 2012 9:30 PM by buy google +1

Leave a Comment

(obligāts) 
(obligāts) 
(brīvizvēles)
(obligāts)