13 messaggi dal 06 gennaio 2006
Ciao a tutti,
ho una soluzione in cui esiste un progetto services dove risiedono i servizi di business che a loro volta utilizzano il pattern repository per l'accesso al db.
come orm utilizzo Entity framework 6.1 db first.
Finchè le entità vengono utilizzate così come EF le genera non ho problemi, quando invece ho la necessità di avere un campo calcolato sulle entità (Es classico, TotaleFattura sull'entità Fattura) quale sarebbe il posto migliore dove mettere questa logica? e come dire a EF che quello è un campo che non deve persistere?

La mia prima idea era quella di aggiungere una proprietà readonly all'entità (magari in una partial) e poi in qualche modo utilizzare un metodo dei servizi di business per il calcolo, ma a questo punto se devo fare una query del tipo "Tutte le fatture che hanno TotaleFattura > 1000" devo prima effettuare la query con EF, poi ToList per avere la lista in locale ed infine la where...a occhio non mi sembra molto ottimizzato.

In generale esiste una best practice per questo tipo di implementazione in un mondo DDD?

Grazie
Ciao
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,

puoi indicare ad EF di non mappare le proprietà calcolate decorandole con l'attributo [NotMapped] oppure, da interfaccia fluente, con il metodo Ignore di EntityTypeConfiguration<TEntityType>.

Tuttavia, perché forzarsi a calcolare ogni volta il totale della fattura; non potresti semplicemente memorizzare anche il totale nella tabella Fatture?
E' un valore che compare in un documento, io lo memorizzerei come tale.

Comunqe, se tu preferisci non memorizzarlo per qualche motivo, potrai comunque ricalcolarlo nell'ambito di una query LINQ (con le perdite prestazionali derivanti da questo calcolo - può darsi che la query risultante tiri in ballo delle subqueries).
//io qui semplifico sommando giusto i valori delle righe
//ma è probabile che tu debba sommare anche altri valori, tipo trasporto, tasse, detrazioni, ecc...
var fatture = contesto.Fatture.Where(fattura => fattura.Righe.Sum(riga => riga.Importo) > 1000);


Questa logica, specie se devi riutilizzarla in più punti dell'applicazione, potresti incapsularla in un extension method tipo questo:
public static class EstensioniFattura 
{
    public static IQueryable<Fattura> ConTotaleMaggioreDi(
      this IQueryable<Fattura> fatture, int valoreMinimo)
    {
      return fatture.Where(fattura => fattura.Righe.Sum(riga => riga.Importo) > valoreMinimo);
    }
}


e poi vai ad usarlo così:
var fatture = contesto.Fatture.ConTotaleMaggioreDi(1000).ToList();


ianselmi ha scritto:

In generale esiste una best practice per questo tipo di implementazione in un mondo DDD?

Puoi valutare le Layered Expression Trees.
Qui trovi slides e presentazione di Andrea Saltarello.
http://www.slideshare.net/andysal/layered-expression-trees-feat-cqrs?next_slideshow=1
https://vimeo.com/35679462

ciao,
Moreno

Enjoy learning and just keep making
13 messaggi dal 06 gennaio 2006
Ciao Moreno,
Come sempre disponibilissimo.

Hai ragione il totale potrei salvarlo, ma era solo un esempio di un campo calcolato e non un caso reale.
L'idea degli extension methods potrebbe andare per' mi perdo la possibilita' di cambiare la logica in base alle mie configurazioni(es due servizi relativi a due ambienti diversi potrebbero avere regole diverse)
L'ultimo metodo rimane quello del calcolo on fly, ma era proprio quello che volevo evitare.
A questo punto mi chiedo se sto pensando in modo sbagliato alla soluzione oppure effettivamente non c'e' altro modo?

Grazie ciao
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,

ianselmi ha scritto:

L'idea degli extension methods potrebbe andare per' mi perdo la possibilita' di cambiare la logica in base alle mie configurazioni


In questo caso puoi ricorrere ad un servizio di dominio.
Nella classe in cui devi calcolare il totale (es. un Controller di ASP.NET MVC, o un ViewModel di WPF) esplicita la sua dipendenza dal servizio.

public FattureController : Controller {
   private readonly ICalcolatoreTotaleFattura calcolatoreTotale;
   public FattureController(ICalcolatoreTotaleFattura calcolatoreTotale){
      this.calacolatoreTotale = calcolatoreTotale;
   }
}

...e poi lo usi così nel momento in cui ti serve:
var totale = this.calcolatoreTotale.CalcolaTotale(fattura);

Dato che ti sei legato ad un'interfaccia (ICalcolatoreTotaleFattura) e non ad un'implementazione concreta, spetterà ad un IoC container darti l'istanza appropriata all'ambiente in cui ti trovi.

ciao,
Moreno
Modificato da BrightSoul il 19 aprile 2015 08.52 -

Enjoy learning and just keep making
13 messaggi dal 06 gennaio 2006
Ciao Moreno,
grazie per le risposte, faccio qualche prova e vediamo come va.

Ciao

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.