none
Repository Problema RRS feed

  • Domanda

  • Ciao a tutti, stavo cercando di sistemare la struttura di un repository generico.

    Sto cercando di capire come posso  utilizzare un metodo che mi restituisce ogni volta il repository giusto.

    Ho una finestra di fatturazione, ogni tipo di fattura viene salvata su una tabella diversa(ad esempio FatturaImmediata,FatturaDifferita etc...) Quindi ho creato un repository generico. per adesso ho creato un metodo per farmi ritornare il repository adatto al tipo di fattura.

    Questa è il codice del mio repository generico:

    public class RepositoryBase<T> where T : class,IEntityBase { private readonly DbSet<T> ctx; internal DbContext context; private readonly UtilityDomain utilityDomain; public RepositoryBase(DbContext _context) { context = _context; ctx = _context.Set<T>(); utilityDomain = new UtilityDomain(); } public void Aggiungi(T oggetto) { ctx.Add(oggetto); } public void Elimina(Expression<Func<T, bool>> predicate) { var entityToDelete = ctx.Where(predicate); if (entityToDelete.Count() != 0) { foreach (var entity in entityToDelete) { ctx.Remove(entity); } } }

     public T Prendi(Expression<Func<T, bool>> predicate)
            {
                var trovato = ctx.FirstOrDefault(predicate);
                return trovato;
            }

    public T PrendiPerId(Guid id) { return ctx.Find(id); } public T PrendiPerId(Guid id,string corpo1,string corpo2,string corpo3) { return ctx.Include(corpo1).Include(corpo2).Include(corpo3).FirstOrDefault(x=>x.Id == id); } } public interface IEntityBase { Guid Id { get; set; } int NumeroRecord { get; set; } int NumeroRiga { get; set; } string Codice { get; set; } DateTime DataCreazione { get; set; } DateTime DataModifica { get; set; } string UsernameLogin { get; set; } string DatabaseLogin { get; set; } string NomePcLogin { get; set; } string CodiceDittaAssociata { get; set; } string RagioneSocialeDittaAssociata { get; set; } }


    Questa invece è la mia classe che dovrebbe ritornarmi il repository adatto in base al tipo fattura:

    public static class DocumentoMerceHelper
        {
            public static dynamic RepositoryDocumenti(string _tipo4, dynamic nuovoCtx)
            {
                   switch (_tipo4)
                {
                    case "VFI":
                        return new RepositoryBase<TestataFatturaImmediataVendita>(nuovoCtx);
                    case "VDT":
                        return new RepositoryBase<TestataDocumentoDiTrasportoVendita>(nuovoCtx);
                    case "VFD":
                        return new RepositoryBase<TestataFatturaDifferitaVendita>(nuovoCtx);
                    case "VNC":
                        return new RepositoryBase<TestataNotaCreditoGenericaVendita>(nuovoCtx);
                    case "VNG":
                        return new RepositoryBase<TestataNotaCreditoGenericaVendita>(nuovoCtx);
                    case "VBU":
                        return new RepositoryBase<TestataBuonoDiConsegnaVendita>(nuovoCtx);
                }
            }
    
    }

    In questo momento mi faccio ritornare un oggetto dynamic, ma in questo modo non posso accedere a tuttii metodi del repository ad esempio al metodo "Elimina" oppure al metodo "Prendi" doved passo un predicate, perche ovviamente nel viewmodel mi dice che non posso usare una lambda expression in un oggetto dinamico.

    Questo è un metodo del mio viewmodel dove richiamo la classe che dovrebbe restituirmi il repository adatto:

     private void AggiornaIdDocumentoAcquistoInFatturaVendita(string _tipo4,Guid? _idDocumentoVendita)
            {
                var newCtx = RitornaNuovoContesto();
    
                var repositoryDocumento = DocumentoMerceHelper.RepositoryDocumenti(_tipo4, newCtx);
                var documento = repositoryDocumento.Prendi(x => x.Id == _idDocumentoVendita);
    }

    Qui mi da errore perche non posso usare una lambda expression in un oggetto dinamico.

    Come potrei risolvere?


    martedì 6 ottobre 2015 08:25

Risposte

  • Ciao,

    la problematica che esponi è abbastanza nota e risiede nel particolare utilizzo che stai facendo del dynamic in congiunzione alle lambda espression. Tieni presente che, con il dynamic, le operazioni che hai scritto verranno risolte a run-time. Questo approccio implica molte conseguenze, partendo da un carattere di stabilità / performances fino ad un carattere di design del software che stai scrivendo.

    Ti faccio un esempio della problematica, ma ti invito a leggere ed approfondire l'argomento:

    var db = Database.Open("DB"); var filter = db.QueryValue("QUERY"); var resultsQuery = db.Query("QUERY @0", filter); var resultsSelect = resultsQuery.Select(i => new ecc...


    In questo caso particolare la problematica risiede nel fatto che, sebbene un metodo Select ritorni come tipo un IEnumerable, il passaggio del filter dynamic renderà il ritorno del Select appunto dynamic.

    Una possibile soluzione al problema sopra descritto potrebbe essere tipizzare il filter oppure dichiarare resultsQuery come un IEnumerable<dynamic>.

    Venendo al tuo caso specifico, potresti semplicemente effettuare un cast di questo tipo:

    ((RepositoryBase<TestataFatturaImmediataVendita>)repositoryDocumento).Prendi(x => x.Id == _idDocumentoVendita);

    Dove il caso è VFI per esempio.

    Saluti :)



    mercoledì 7 ottobre 2015 09:50

Tutte le risposte

  • Ciao,

    la problematica che esponi è abbastanza nota e risiede nel particolare utilizzo che stai facendo del dynamic in congiunzione alle lambda espression. Tieni presente che, con il dynamic, le operazioni che hai scritto verranno risolte a run-time. Questo approccio implica molte conseguenze, partendo da un carattere di stabilità / performances fino ad un carattere di design del software che stai scrivendo.

    Ti faccio un esempio della problematica, ma ti invito a leggere ed approfondire l'argomento:

    var db = Database.Open("DB"); var filter = db.QueryValue("QUERY"); var resultsQuery = db.Query("QUERY @0", filter); var resultsSelect = resultsQuery.Select(i => new ecc...


    In questo caso particolare la problematica risiede nel fatto che, sebbene un metodo Select ritorni come tipo un IEnumerable, il passaggio del filter dynamic renderà il ritorno del Select appunto dynamic.

    Una possibile soluzione al problema sopra descritto potrebbe essere tipizzare il filter oppure dichiarare resultsQuery come un IEnumerable<dynamic>.

    Venendo al tuo caso specifico, potresti semplicemente effettuare un cast di questo tipo:

    ((RepositoryBase<TestataFatturaImmediataVendita>)repositoryDocumento).Prendi(x => x.Id == _idDocumentoVendita);

    Dove il caso è VFI per esempio.

    Saluti :)



    mercoledì 7 ottobre 2015 09:50
  • ciao... :) 

    già avevo provato ad eseguire il cast ma mi dice :

    Ulteriori informazioni: Impossibile convertire in modo implicito il tipo 'Sedna.Domain.Repository.RepositoryBase<Sedna.Domain.Entity.TestataVenditaContoVendita>' in 'Sedna.Domain.Repository.RepositoryBase<Sedna.Domain.Entity.Base.IEntityBase>'

    Vorrei anche solo poter riuscire a vedere i metodi del repository che mi faccio ritornare

    mercoledì 7 ottobre 2015 10:00
  • Ciao :),

    forse non mi sono spiegato bene ;) ma cmq no problem, cerco di rispiegarti:

    Il concetto alla base di questo discorso è che dato che tu stai usando dynamic(alla cui base c'è l'istanza di un Generics) in congiunzione con espressioni lambda, non puoi se non tramite una tipizzazione del cast per esempio per il tipo TestataFatturaImmediataVendita, nel tuo caso il _tipo4 == "VFI".

    Ti inviterei a studiare per i Generics i concetti di Covarianza e Controvarianza per capire quello di cui stiamo parlando ;)

    Esistono tuttavia molte soluzioni al tuo problema, la più dinamica che mi viene in mente e che non cambia di molto il tuo codice è quella di usare refection per l'invocazione dei metodi del repository, per esempio potresti trasformare l'helper in questo modo:

    public static class DocumentoMerceHelper { public static Type GetBaseRepositoryT(string _tipo4) { switch (_tipo4) { case "VFI": return typeof(TestataFatturaImmediataVendita);

    //ecc... } return null; }

            public static Expression GetExpression(string _tipo4, Guid? _idDocumentoVendita)
            {
                switch (_tipo4)
                {

                    case "VFI":
                        Expression<Func<TestataFatturaImmediataVendita, bool>> exp = x => x.Id == _idDocumentoVendita;
                        return exp;
                }
                return null;
            } }

    poi potresti nel metodo sull'object layer che chiama di fatto il metodo del base repository fare qualcosa del genere:

    private void AggiornaIdDocumentoAcquistoInFatturaVendita(string _tipo4, Guid? _idDocumentoVendita) { var newCtx = RitornaNuovoContesto(); Type genericRepositoryType = typeof(RepositoryBase<>); Type makedGenericRepositoryBase = genericRepositoryType.MakeGenericType(DocumentoMerceHelper.GetBaseRepositoryT(_tipo4)); object repositoryBaseInstance = Activator.CreateInstance(makedGenericRepositoryBase, newCtx);

    //Si potrebbe per esempio concatenare a _tipo4 qualcosa che identifichi la lambda particolare da eseguire... IEntityBase documento = (IEntityBase)repositoryBaseInstance.GetType().GetMethod("Prendi", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).Invoke(repositoryBaseInstance, new object[] { DocumentoMerceHelper.GetExpression(_tipo4, _idDocumentoVendita) }); }

    Questi sono solo esempi che servono a focalizzare il problema, non sono da intendersi come soluzioni definitive ;)

    Altre soluzioni potrebbero essere ripensare un po' su quale deve essere effettivamente il dominio e la modalità per gestione della mappatura che vuoi tra _tipo4 e i tipi che implementano IEntityBase.

    Ti consiglio in proposito di studiare IOC, questo per capire come effettuare l'injection in maniera dinamica.

    Spero di esserti stato utile,

    Saluti ;)

    N.B. ho effettuato alcune modifiche per chiarificare l'esempio, Saluti :)












    • Modificato aruta mercoledì 7 ottobre 2015 15:43
    • Proposto come risposta Fabio Mannis mercoledì 7 ottobre 2015 16:10
    mercoledì 7 ottobre 2015 14:53