[NHibernate of Linq] Filteren op berekende properties

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Introductie
Stel ik heb de volgende tabel:

code:
1
2
3
4
5
6
Contracts
-------------
ID
CustomerID
DateLastPayment
Valid


En dit is mijn object:

code:
1
2
3
4
5
6
7
Contract
-------------
ID
CustomerID
LastPaymentDate
Valid
IsOverdue


Zoals je kan zien heeft mijn object een property die niet in mijn tabel zit: IsOverdue
Deze propertie wordt berekend met deze method:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public virtual bool IsOverdue
{
   get
   {
      if (Valid && LastPaymentDate < System.DateTime.Now.AddDays(-31) )
      {
         return true;
      }
      else
      {
         return false;
      }
   }
}



Vraag
Ik zou graag willen weten of het mogelijk is met Nhibernate of Linq om alle contracten op te halen die overdue zijn. Hiermee bedoel ik dus alle contracten waarvoor geldt (IsOverdue == true).

Met SQL lukt dat natuurlijk makkelijk:

SQL:
1
2
3
select * from Contracts
where Valid = 1
and ( DateLastPayment< dateadd(dd,-31, GETDATE() ) )


En ik kan deze code ook wel in Nhibernate of in Linq gaan schrijven, maar ik wil dat dus niet doen, maar eigenlijk de property IsOverdue gebruiken.

Misschien een beetje teveel van het goede, omdat dit een combinatie is van Linq-to-SQL en Linq-to-Objects, maar het lijkt me toch wel een interessant vraagstuk.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Overigens, het lukt jammergenoeg niet met Linq op deze manier:

C#:
1
2
3
var contracten = from c in db.Contracten select c;

var enkeleContracten = from e in contracten where e.IsOverdue == true select e;



Het eerste gedeelte gaat natuurlijk prima:
C#:
1
var contracten= from c in db.Contracten select c;

Hij haalt netjes alle contracten op uit de database.

Maar het tweede stuk:
C#:
1
var enkeleContracten = from e in contracten where e.IsOverdue == true select e;

....dat gaat Linq ook uitvoeren op de database. Hij snapt dus nog niet dat ik deze query op een verzameling objecten wil uitvoeren, en niet op een database.

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:25
Waarom zou je willen dat dit uitgevoerd op je objecten , en niet op de DB ? Dat is dan toch gigantisch on-performant ?

Dwz dat je dan eerst al je contracten gaat ophalen, en dat ieder contract dan moet bekeken worden, om te zien of ie OverDue is of niet .... Lijkt me geen goed plan.

Welke query genereert LINQ to SQL eigenlijk ?
En hoe handelt NHibernate dit af ? Maw, welke query genereert NHibernate ?

Waarom wil je dit eigenlijk zo doen ? Als LINQ-to-SQL en/of NHibernate deze constraint gaan vertalen in hun query, dan is dat toch perfect ? Je logica blijft centraal, en LINQ to SQL /NHibernate zorgt ervoor dat er een performante query uitgevoerd wordt. al geloof ik niet dat zei je formula-property kunnen vertalen naar een geschikte where clause .

Om je logica centraal te houden, en met een performante query op de proppen te kunnen komen, zou ik 'IsOverdue' geen property maken van je Contract class, maar zou ik gebruik maken van het specification pattern, en een 'IsContractOverdueSpecification' oid maken.

Die specification kan dan een method <code>IsContractOverdue</code> bevatten die een Contract als argument neemt, en true of false returned.
Daarnaast kan die specification ook een method bevatten die de contracten die overdue zijn uit de datastore ophaalt. (Al dan niet gebruik makend van een repository).

[ Voor 12% gewijzigd door whoami op 24-08-2008 23:13 ]

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • The - DDD
  • Registratie: Januari 2000
  • Laatst online: 12-06 00:33
Kwestei van de inhoud van je if statement in de overdue methode vertalen in de juiste query syntax lijkt me. Je berekent een grensdatum en je vraagt alles op waarvan de lastpayment voor die grensdatum ligt mits het account valid is. Snap niet wat daar nou zo moeilijk aan moet zijn.

Misschien dat dit helpt...
http://msdn.microsoft.com/en-us/library/bb882657.aspx

Ik ken overigens Linq niet... :)

[ Voor 17% gewijzigd door The - DDD op 25-08-2008 00:12 ]


Acties:
  • 0 Henk 'm!

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Verwijderd schreef op zondag 24 augustus 2008 @ 20:36:
Overigens, het lukt jammergenoeg niet met Linq op deze manier:

C#:
1
2
3
var contracten = from c in db.Contracten select c;

var enkeleContracten = from e in contracten where e.IsOverdue == true select e;



Het eerste gedeelte gaat natuurlijk prima:
C#:
1
var contracten= from c in db.Contracten select c;

Hij haalt netjes alle contracten op uit de database.

Maar het tweede stuk:
C#:
1
var enkeleContracten = from e in contracten where e.IsOverdue == true select e;

....dat gaat Linq ook uitvoeren op de database. Hij snapt dus nog niet dat ik deze query op een verzameling objecten wil uitvoeren, en niet op een database.
Wat logisch is, want 'contracten' is een IQueryable, en dan wordt de linq query een Expression tree.

Wat je zou kunnen doen in het 1e gedeelte is:
var contracten = (from c in db.Contracten select c).ToList();

maar ik snap idd niet waarom je dit in vredesnaam in memory zou willen doen, je laadt nu nl. alle conrtacten in memory.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
EfBe schreef op maandag 25 augustus 2008 @ 09:13:
maar ik snap idd niet waarom je dit in vredesnaam in memory zou willen doen, je laadt nu nl. alle conrtacten in memory.
Ik ben even wat aan het stoeien met Linq en Nhibernate...de randen opzoeken van wat mogelijk is. Het ophalen van alle contracten en dan in memory er doorheen zoeken is geen situatie die je in een echt systeem zou willen.

Wat mij wel handig lijkt is in C# bepaalde berekeningen definieren, die vervolgens door de parser worden omgezet naar sql:

Een Actie met een start- en einddatum, met als property AantalDagenVerschil. Het zou mooi zijn als de parser dan snapt dat als ik AantalDagenVerschil > 40 wil, dat hij dat dan naar sql vertaald met start- en einddatum.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
whoami schreef op zondag 24 augustus 2008 @ 23:09:
Als LINQ-to-SQL en/of NHibernate deze constraint gaan vertalen in hun query, dan is dat toch perfect ? Je logica blijft centraal, en LINQ to SQL /NHibernate zorgt ervoor dat er een performante query uitgevoerd wordt. al geloof ik niet dat zei je formula-property kunnen vertalen naar een geschikte where clause .
Het punt is dus dat Linq en NHibernate het niet zondermeer kunnen vertalen. De geplaatste code geeft een error omdat er geen mapping is met een database veld.

Het is niet echt een groot probleem natuurlijk, omdat je dit soort dingen makkelijk in HQL, of met Criteria kan oplossen. Maar ik vind 't op zich wel een aardig idee als de parser mijn C# code kan omzetten naar SQL.

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:25
Dat ze het niet gingen kunnen omzetten, leek me wel logisch. :)

Vandaar dat ik denk dat een 'Specification' gebruiken de beste oplossing is voor dit probleem.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Verwijderd schreef op maandag 25 augustus 2008 @ 10:35:
[...]
Ik ben even wat aan het stoeien met Linq en Nhibernate...de randen opzoeken van wat mogelijk is. Het ophalen van alle contracten en dan in memory er doorheen zoeken is geen situatie die je in een echt systeem zou willen.
De Linq to NHibernate provider is niet dermate volwassen dat je er nu alles mee kunt, hun originele setje tests doet het nl. al niet, laat staan de wat meer moeilijkere zaken.
Wat mij wel handig lijkt is in C# bepaalde berekeningen definieren, die vervolgens door de parser worden omgezet naar sql:

Een Actie met een start- en einddatum, met als property AantalDagenVerschil. Het zou mooi zijn als de parser dan snapt dat als ik AantalDagenVerschil > 40 wil, dat hij dat dan naar sql vertaald met start- en einddatum.
Een beetje linq provider laat je methods en properties mappen op db constructies. AantalDagenVerschil moet dan wel een DB equivalent hebben. Als dat in-memory eind-startdatum doet als code in de property dan is dat natuurlijk niet te vertalen naar SQL, want de compiler en de linq provider gaan geen IL reverse engineeren at runtime. Wat je wel kunt doen is een where opgeven met (a.EindDatum - a.StartDatum) > 40

[ Voor 3% gewijzigd door EfBe op 25-08-2008 12:30 ]

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com

Pagina: 1