Správičky 2 270 Blogy 577 Fórum 14 074

Prehľad diskusie

photo
IQueryable join
malybirko
6. 2. 2012 10:32:07
photo
RE: IQueryable join
xxxmatko
6. 2. 2012 13:15:08
photo
RE: IQueryable join
Liero
6. 2. 2012 16:02:12
photo
RE: IQueryable join
malybirko
6. 2. 2012 16:23:52
photo
RE: IQueryable join
malybirko
6. 2. 2012 16:24:51
photo
RE: IQueryable join
malybirko
6. 2. 2012 16:36:43
photo
RE: IQueryable join
Liero
6. 2. 2012 17:25:33
photo
RE: IQueryable join
xxxmatko
6. 2. 2012 17:25:36
photo
RE: IQueryable join
Liero
6. 2. 2012 17:29:32
photo
RE: IQueryable join
malybirko
6. 2. 2012 19:04:04
photo
RE: IQueryable join
xxxmatko
6. 2. 2012 19:26:10
photo
RE: IQueryable join
liero
6. 2. 2012 23:48:56
photo
RE: IQueryable join
.
7. 2. 2012 7:30:58
photo
RE: IQueryable join
malybirko
7. 2. 2012 8:37:17
photo
RE: IQueryable join
.
7. 2. 2012 9:52:12
photo
RE: IQueryable join
vlko
7. 2. 2012 13:08:30
photo
RE: IQueryable join
malybirko
7. 2. 2012 13:16:38
photo
RE: IQueryable join
T
7. 2. 2012 13:21:31

IQueryable join

photo
malybirko
6. 2. 2012 10:32:07
Body: 325
Najaktívnejší č.: 42

IQueryable join

Pouzival niekto Join s Iqueriable interfacom.

Chcel by som aby pri nacitavani si obratov si objekt nenacitaval informacie o referencii s DB ale zeby som mu uz priradil uz predom nacitany objekt.

Vlastne som skonstruoval takuto  zakernost 

var tmp = FisApplication.Instance.Stock.GetTurnovers(id, dfrom, dto);
var product =  _productCache.GetData().Where(p => p.ID == id);
tmp = tmp.Join(product, t => t.ProductID, p => p.ID, (t, p) => new ProductTurnover(){ ID = t.ID, Period = t.Period, ProductID = t.ProductID, TaxRate = t.TaxRate, PositiveAmount = t.PositiveAmount, NegativeAmount = t.NegativeAmount, PurchasePrice = t.PurchasePrice, SellingPrice = t.SellingPrice});

Pri exekucii queryplanu mi vyhodi pri System.NotSupportedException. Unable to create a constant value of type 'FisLogic.Data.Product'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.

Napadlo ma este ine riesenie len neviem ako vytvorim nejaku metodu aby jeden z jej parametrov bol lambdaexpression tak keby aspon toto ste mi poradili ako spravit lambda metodu . 

[Reakcia]

photo
xxxmatko
6. 2. 2012 13:15:08
Body: 725
Najaktívnejší č.: 27

RE: IQueryable join

Lambda vyraz je len skratene volanie nejakeho delegata, napr.:

ak mas takuto triedu

public class Person
{
    public string Name;
    public int Age;
}

potom mozes definovat napr. takuto metodu:

publicvoid GetList(Func<Person, object> propSelector, Func<Person, bool> condition)
{
    object newObj = propSelector(/*instancia Person*/);
    bool cond = condition(/*instancia Person*/);
}

a nasledne volat tuto metodu:

GetList(person => new
{
    name = person.Name,
    age = person.Age
}, p => p.Age > 30);

ak by si chcel s danym lambda vyrazom pracovat ak s datami (vyrazove stromy) staci vstupne argumenty este wrapnut do Expression<>, takto:

protected void GetList(Expression<Func<Person, object>> propSelector, Expression<Func<Person, bool>> condition)
{

}

 

 

xxxmatko

[Reakcia]

photo
Liero
6. 2. 2012 16:02:12
Body: 3780
Najaktívnejší č.: 8

RE: IQueryable join

1. preco si vytvoris premennu tmp, ktora je nejakeho typu (asi List<Turnover) a potom do nej nejaku inu kolekciu?

2. skontroluj si, ci v tom vyslednom Select(new ProductTurnover { })  pri volani v konstruktora pouzivas v nutry labda vyrazu iba primitivne typy (int, string atd..). Ak tam mas aj nieco ine, 

3. nemas nejaku inner exception? Ked napises nejaky Linq vyraz, on sa nespusti hned, ale az neskor, ked to je nevyhnutne. Je mozne ze chyba nastala uplne inde, akurat az teraz sa prejavila. Skus si dat za kazdym Linq vyrazom .ToList(), to sposobi, ze sa ten vyraz spusti hned.

4. skus postnut stacktrace

5. vyskusaj pisat linq vyrazy tak, ze to rozbijes do viacerych riadkov, uvidis ze sa ti to zapaci. Je to ovela citatelnejsie, potom usetris cas sam sebe, aj inym.
 

napr:
var a = db.Products
  .Where(...)
  .Join(...)
  .Select(p => new
  {
     PropertyA = p.A,
     PropertyB = p.B
  })

mozog programatora, teda aspon ten moj, nieje stavany na spracovanie
viacerych funkcii v jednom riadku :)

 

[Reakcia]

photo
malybirko
6. 2. 2012 16:23:52
Body: 325
Najaktívnejší č.: 42

RE: IQueryable join

xxxmatko dakujem .

Co vlastnepotrebujem dosiahnut je aby sa mi nezavolal lazyloading na jednej property

konkretne tejto:

 public virtual string ProductName
        {
            get
            {
                if (this.Product != null)
                {
                    return this.Product.Name;
                }
                return String.Empty;
            }
        }

Produkt je vlastne navigation property a natahhuje sa Dynamicky na vyziadanie.  pocas behu programu ked sa mi data vlastne zobrazuju do DGW tak mi hore spominana property ProductName vyhodi System.AccessViolationException' occurred in System.Data.SqlServerCe.dll 

Potreboval by som aby  sa  Property Produkt  priradila uz z nacitaneho zoznamu produktov. Skusal som to najprv pomocou metody Join co ma v sebe Interface IQueryable ale vyhodi mi chybu co som 

napisal v prvom poste.

tak som vlastne dnes vymyslel nasledovny bazmek:

   _turnoverCache.JoinData<Product>("joinProducts", _productCache.GetData(), (p, t) => { return p.ID == t.ProductID; }, (t, p) => { t.Product = p; return t; });

 

 

  • "joinProducts" je len nazov kluca v Dictionary 
  • _productCache.GetData() vrati zoznam produktov nacitany v mojom app buffry pre produkty
  • (p, t) => { return p.ID == t.ProductID; } toto by mal byt delegat co selectne spravny produkt z buffra 
  •  (t, p) => { t.Product = p; return t; } a toto je delegat ktory priradi uz selectnuty produkt do objektu ProductTurnover 

lenze chyba s AccesViolation my vyskakuje stale.  mam nejaku chybu v definicii tych delegatov?

 

 


 

 

[Reakcia]

photo
malybirko
6. 2. 2012 16:24:51
Body: 325
Najaktívnejší č.: 42

RE: IQueryable join

PS: bodla by sa konecne editacia postu. lebo niekedy pisem ako  ...  >..<

[Reakcia]

photo
malybirko
6. 2. 2012 16:36:43
Body: 325
Najaktívnejší č.: 42

RE: IQueryable join

@liero:

1. tmp je  je v skutocnosti este len query takze prakticky neobsahuje este konkretne data a nemam rad zbytocne premenne

2. Mno konkretne Produkt nieje primitiivny typ a ten nastavit by som praveze portreboval

3. iner exception nieje  

4.stack trace je nalsedovny

   at System.Data.Objects.ELinq.ExpressionConverter.ConstantTranslator.TypedTranslate(ExpressionConverter parent, ConstantExpression linq)
   at System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Data.Common.CommandTrees.ExpressionBuilder.Internal.EnumerableValidator`3.Validate(IEnumerable`1 argument, String argumentName, Int32 expectedElementCount, Boolean allowEmpty, Func`3 map, Func`2 collect, Func`3 deriveName)
   at System.Data.Common.CommandTrees.ExpressionBuilder.Internal.ArgumentValidation.CreateExpressionList(IEnumerable`1 arguments, String argumentName, Boolean allowEmpty, Action`2 validationCallback)
   at System.Data.Common.CommandTrees.ExpressionBuilder.Internal.ArgumentValidation.ValidateNewCollection(IEnumerable`1 elements, DbExpressionList& validElements)
   at System.Data.Objects.ELinq.ExpressionConverter.NewArrayInitTranslator.TypedTranslate(ExpressionConverter parent, NewArrayExpression linq)
   at System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
   at System.Data.Objects.ELinq.ExpressionConverter.ConstantTranslator.TypedTranslate(ExpressionConverter parent, ConstantExpression linq)
   at System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
   at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, DbExpression& source, DbExpressionBinding& sourceBinding, DbExpression& lambda)
   at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)
   at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
   at System.Data.Objects.ELinq.ExpressionConverter.TranslateSet(Expression linq)
   at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.JoinTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)
   at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
   at System.Data.Objects.ELinq.ExpressionConverter.Convert()
   at System.Data.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
   at System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
   at System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at OravaTop.Net.Forms.TurnoverForm.LoadProduct(Guid id) in C:\Project\Fisdata\Solutions\FisData Partner\OravaTop.Net\Forms\TurnoverForm.cs:line 193
   at OravaTop.Net.Forms.TurnoverForm.<Recalculate>b__7() in C:\Project\Fisdata\Solutions\FisData Partner\OravaTop.Net\Forms\TurnoverForm.cs:line 172
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

 

5. Ok beriem na vedomie. za toto ma nenavideli ani na vyske lebo mne to problem nerobilo dat niekolko metod do riadku 

[Reakcia]

photo
Liero
6. 2. 2012 17:25:33
Body: 3780
Najaktívnejší č.: 8

RE: IQueryable join

RE:
1. vidis, ale tu je presne ten problem. ja z vypisu kodu nemozem vediet, co je to tmp, lebo ani nazov mi nic nepovie, ani to co je na pravej strane.

 Keby si to napisal var turnoverQuery = ..., nebolo by to hned lepsie?

premenna je preto premenna aby si ju pomenoval :) Obzvlast vtedy, ked ju chces ukazovat aj niekomu inemu. To nema ziaden vplyv na performance, skor si ustraz spravny scope pre danu premennu.

preco ta trapi vytvaranie novej premennej? Ved ona sa aj tak vytvori nova referencia, nema to ziaden performance efekt. Pisat kod, je ako pisat beletriu. Musi to byt pribeh, kde kazda veta dava zmysel. Mozes v tom pribenu nazyvat niekoho tmpOsoba1 a potom neskor niekoho ineho nazyvat tiez tmpOsoba1. Logicky to je sice spravne ale kto tomu bude rozumiet? Co myslis, ako sa lisi kvalitny kod od nekvalitneho? poctom premennych, alebo jednoduchostou, citatelnostou, vystiznostou atd?



1. Nevidim, kde pouzivas ten ProductName
2. skus nahradit druhy riadok tymto: 
var product = _productCache.GetData().Where(p => p.ID == id).ToList();

[Reakcia]

photo
xxxmatko
6. 2. 2012 17:25:36
Body: 725
Najaktívnejší č.: 27

RE: IQueryable join

Problem je podla mna v tom, ze dana LINQ query nemoze byt spravne interpretovana ako SQL vyraz, to sa moze stat ak v LINQ query kombinujes lokalne data s datami v db, inak povedane priradenie tvojej navigacnej property nevie EF prelozit do SQL.

Vid priklad: Mam v db tabulku uzivatelov (Users) a tabulku roli (Roles), tie su prepojene cez tabulku UsersRoles. Zoznam roli mam nacitany v pamati. Chcem urobit dopyt ktory mi pre priradi rolu, ktora je v pamati pre kazde uzivatela, ktorych nacitam z db:

using(var db = new DbContext())
{
    var rolesCache = db.Roles.Select(r => r).ToList();

    // Toto neprejde
    var query1 = db.UsersRoles.Select(ur => new 
    {
            Id = ur.UserID,
            Role = rolesCache.FirstOrDefault(r => r.ID == ur.RoleID)
    });
}

Takto to neprejde a zahlasi tu istu chybu aku hlasi tebe. Ak vsak aj zoznam uzivatelov ulozim do pamate tak uz to prejde:

using(var db = new DbContext())
{
    var rolesCache = db.Roles.Select(r => r).ToList();

    var usersRoles = db.UsersRoles.Select(ur => ur).ToList();

    // Toto prejde
    var query0 = usersRoles.Select(ur => new
    {
        Id = ur.UserID,
        Role = rolesCache.FirstOrDefault(r => r.ID == ur.RoleID)
    });
}

Ja by som to riesil asi tak ze z db si nacitam data s tabulky ktore potrebujem s vypnutym lazy loadingom (ak potrebujem nejake ine navigacne property mat nacitane pouzijem LoadWith()) a potom vo for cykle priradim nacitanym objektom referencne properties z cache.

xxxmatko

[Reakcia]

photo
Liero
6. 2. 2012 17:29:32
Body: 3780
Najaktívnejší č.: 8

RE: IQueryable join

problem je v tom, ze sa do sql dotazu snazis poslat Product ako parameter. Musis si nacitat turnovery, producty a potom ich joinut na klientovy. Alebo si sprav storku, ktora ti to vrati uz joinute. Alebo posli do selectu do where podmienky zoznam idcok.

[Reakcia]

photo
malybirko
6. 2. 2012 19:04:04
Body: 325
Najaktívnejší č.: 42

RE: IQueryable join

Okej takze uz som sa naucil  ze kombinoovat sql dotaz a klientske data nieje mozne :D

 

@liero: ProductName sa vyuziva v nabindowanom datagridview.

2.Mam vytvoroenu triedu ktora v sebe vykonava funkcnost obdobnu s ToList(). GetData() vracia tento list.

 _productCache a _turnoverCache su jej instancie, Pri inicializacii jejposlem query, ktoru  prechadzaju vo foreach cykle  a jednotlive nacitane polozky ukladaju do Listu. Priebezne pocas nacitavania, kazdych 300 poloziek, vyvolaju event ktory napr updatne progresbar a zobrazi dovtedy nacitane data.

do tejto triedy som dnes vytvoril metodu JoinData,  ktora z daneho zoznamu poloziek na zaklade prveho delegata vyberie potrebne polozky, v tomto pripade produkty a druhy delegat vravi ako dane polozky spracovat. v mojom pripade Priradit Turnoveru dany produkt.

Mam poslat zdrojaky?

 

 

 

[Reakcia]

photo
xxxmatko
6. 2. 2012 19:26:10
Body: 725
Najaktívnejší č.: 27

RE: IQueryable join

Kombinovat klientske data s db datami cez LINQ mozes, dolezite ako ich kombinujes.

Otazkou je aj to ze ci je v tvojom pripade lepsie setrit db traffic kombinovat nacitanie s datami ktore uz mas nacitane v cache alebo nie.

xxxmatko

[Reakcia]

photo
liero
6. 2. 2012 23:48:56
Body: 3780
Najaktívnejší č.: 8

RE: IQueryable join

@malybirko: sice sa smejes, ale tu ide o principialny problem, nie technicky problem nejakeho linqu.

keby si videl robotnika,
1. ktory ma na stavbe furik piesku
2.  ale na urobenie betonu potrebuje aj strk
3.  a tento robotnik by s furikom piesku isiel na strkovisko, tam by ho zmiesal so strkom a potom s dvoma furikmi isiel naspat,
no  nepovedal by si mu, ze to je cele zle? nebolo by rozumnejsie namiesto tychto troch ciest furikom, iba doviest jeden furik strku na stavbu a zmiesat to tam? To co ty robis, su preste tie tri furiky.


zabudni na to co si doteraz napisal a skus sa na cely problem pozriet este raz.


ked uz mas v cache produkty aj turnovery, naco liezt do databazy?

ked chces turnoveru priradit produkt, tak nemoze mat turnover property Product? napr:

 

public Product Product
{
 get
 {
  if (_Product == null)
   _Product = productCache.FirstOrDefault(p => p.ID = this.ProductID)
  return _Product;
 }
}
private Product _Product;

 

[Reakcia]

photo
.
7. 2. 2012 7:30:58
Body: 1150
Najaktívnejší č.: 22

RE: IQueryable join

Presne to s property ako ukazal liero som chcel napisat... (bez prikladu s furikom :)). Podla mna je to najcistejsie riesenie - hned vidis o co sa jedna a nemusis riesit problemy o ktorych si pisal.

[Reakcia]

photo
malybirko
7. 2. 2012 8:37:17
Body: 325
Najaktívnejší č.: 42

RE: IQueryable join

@liero:

Moja POCO trieda ProduttTurnover vypada takto

 public partial class ProductTurnover
    {
        public  Guid ID
        {
            get;
            set;
        }

        public  decimal NegativeAmount
        {
            get;
            set;
        }

        public  decimal PositiveAmount
        {
            get;
            set;
        }

        public  DateTime Period
        {
            get;
            set;
        }

        public virtual Product Product
        {
            get;
            set;
        }

        public  Guid ProductID
        {
            get;
            set;
        }

        public  decimal PurchasePrice
        {
            get;
            set;
        }

        public  decimal SellingPrice
        {
            get;
            set;
        }

        public virtual Receipt Receipt
        {
            get;
            set;
        }

        public Guid ReceiptID
        {
            get;
            set;
        }

        public int ReceiptType
        {
            get;
            set;
        }

        public string TaxGroup
        {
            get;
            set;
        }

        public double TaxRate
        {
            get;
            set;
        }


        public virtual string FullType
        {
            get
            {
                if (ParagonTypes.GetType(this.ReceiptType) != null)
                {
                    return ParagonTypes.GetType(this.ReceiptType).Name;
                }
                else
                {
                    return this.ReceiptType.ToString();
                }
            }
        }

        public virtual string ProductName
        {
            get
            {
                if (this.Product != null)
                {
                    return this.Product.Name;
                }
                return String.Empty;
            }
        }

        public virtual string FullTax
        {
            get
            {
                return String.Format("{0:#0.00%}", this.TaxRate);
            }
        }

        public virtual decimal SellingPriceBrutto
        {
            get
            {
                return this.SellingPrice * (1 + (decimal)this.TaxRate);
            }
        }

        public virtual decimal PurchasePriceBrutto
        {
            get
            {
                return this.PurchasePrice * (1 + (decimal)this.TaxRate);
            }
        }
}

Propety Produkt tam mam.  

lenze ORM mi vrati Proxytriedu a  ta snazi automaticky sama nacitat z DB, comu chcem ja zamedzit kedze  tie Produkty uz nacitane mam. tak som ich chcel priradit tomu turnoveru pocas nacitavania a vyuzit rovno ten cyklus, ktorym si nacitavam turnovery do cache. Ze to nieje problem linq som uz pochopil.  

Tak  som si vytvoril  dvoch delegatov. z daneho datoveho zdroja na zaklade  prveho delegata vybere sa  vhodny prvok a za pomoci druheho delegata ho prilepim k prave nacitanemu obratu

Ad priklad s furikom:  nasipavam do neho piesok a popritom strk ktory uz mam davno pri sebe na vedlajsej kope

[Reakcia]


photo
vlko
7. 2. 2012 13:08:30
Body: 35110
Najaktívnejší č.: 1

RE: IQueryable join

netreba vypnut lazyloading, treba zapnut eager loading .Include()

[Reakcia]

photo
malybirko
7. 2. 2012 13:16:38
Body: 325
Najaktívnejší č.: 42

RE: IQueryable join

@dot: zatial lazy loading necham zapnuty aby som jeho vypnutim nesprznil aj to co je funkcne ,  postupne sa snazim kod trosku  upratat aby nebol na tom zavisly

@vlko Include vyuzivam len nie vsetky referencie. privela include malo  cititelny vpliv na niektore operacie.

[Reakcia]

photo
T
7. 2. 2012 13:21:31
Body: 16735
Najaktívnejší č.: 2

RE: IQueryable join

treba to schovat za fasadu(transaction script + dto) ako bolo uz x krat napisane a rozumne vyuzivat tak lazy ako i eager ale za fasadou. Rozumne znamena znamena ze eager ide vzdy cely aggregat a lazy referencovany aggregat z ineho aggregatu.

Tomáš Zeman, MCSD.NET, MCPD

[Reakcia]



Najaktívnejší užívatelia
1. 35110 b. photo vlko
2. 16735 b. photo T
3. 15560 b. photo spigi
4. 6635 b. photo dudok
5. 5705 b. photo slavof
6. 5205 b. photo siro
7. 4745 b. photo duracellko
8. 3780 b. photo Liero
9. 3690 b. photo lubolacko
10. 3625 b. photo jakub