24 messaggi dal 10 aprile 2003
Ciao,
stavo facendo qualche prova con ninject, Entity frameWork 4.3 e 2 classi.
Una classe implementa l'altra come LIST.
Utilizzardo i repository che mi crea in automatico ninject, ho notato che i repository non mi salvano i dati della classe implementata come LIST.
Penso che sia dovuto perchè ogni repository ha un suo DBContext e facendo le operazioni di CRUD su una, l'altra non si aggiorna.
Volevo sapere se qualcuno ha già integrato una UnitOfWork in maniera tale di utilizzare una DBContext unica per tutte.
O forse sbaglio il ragionamento...
Modificato da Davide_Sangalli il 15 febbraio 2012 14.05 -
5.610 messaggi dal 09 febbraio 2002
Contributi
ciao,

Davide_Sangalli ha scritto:

Penso che sia dovuto perchè ogni repository ha un suo DBContext e facendo le operazioni di CRUD su una, l'altra non si aggiorna.


sì, penso che il problema sia quello. Immagino che Ninject, nell'istanziare ciascun repository, risolva la sua dipendenza dal DbContext iniettandogli ogni volta una nuova istanza.

Dovresti far gestire il ciclo di vita del DBContext a Ninject, in modo che l'istanza iniettata sia sempre la stessa, fintanto che ci si trova all'interno della stessa richiesta web.

Ad esempio, se il tuo repository possiede un costruttore fatto così:
public class ClienteRepository : IClienteRepository {
  public ClienteRepository(MioDbContext contesto){...}
}

Allora aggiungi questa riga ai binding di Ninject.
kernel.Bind<MioDbContext>().ToSelf().InRequestScope();
Il metodo .InRequestScope() farà in modo che solo un'istanza possa essere generata per la richiesta corrente.

ciao

- So what you're saying is, if we get in trouble, there's no one to help us out?
- I'm afraid not.
- Fantastic!
24 messaggi dal 10 aprile 2003
grazie della risposta
Ho usato una repository generica e adesso mi funzionano i collegamenti automatici quando creo una nuova classe1 e nuovi oggetti sulla classe2.
Mi funziona anche aggiornamento/cancellazione/modifica (utilizzando lo State su DbContext) sulla classe2 quando una classe1 è già esistente.
L'unica cosa che non mi funziona è la creazione di una nuova classe2 quando la classe1 già esiste (il campo creato automaticamente da EF viene valorizzato a NULL).

Ho provato anche ha inserire il SingleTon ma non funziona.
Tutto il resto mi funziona, con e senza il comando su ninject

non capisco :-(
Modificato da Davide_Sangalli il 17 febbraio 2012 15.07 -
5.610 messaggi dal 09 febbraio 2002
Contributi
ciao,
non riesco a riprodurre il problema; penso di non aver ben compreso la situazione in cui ti trovi. Prova a postare un po' di codice.

Davide_Sangalli ha scritto:

L'unica cosa che non mi funziona è la creazione di una nuova classe2 quando la classe1 già esiste
Dunque, classe1 ha una proprietà di navigazione che tu valorizzi con una nuova istanza di classe2. Ma classe2, dopo averla istanziata, l'hai passata al metodo .Add del suo repository?

Davide_Sangalli ha scritto:

Ho provato anche ha inserire il SingleTon ma non funziona.

No no, non usare .InSingletonScope(), può succedere un casino. L'ObjectContext non è thread safe e quindi potresti arrivare ad avere oggetti non integri se lasci che venga riutilizzato lo stesso contesto per le richieste di più utenti.

ciao
Modificato da BrightSoul il 17 febbraio 2012 23.15 -

- So what you're saying is, if we get in trouble, there's no one to help us out?
- I'm afraid not.
- Fantastic!
24 messaggi dal 10 aprile 2003
Ho rimesso il requestscope ...
Ho visto che istanziavo un dbcontext per ogni repository! Adesso dovrebbe essere a posto ma non ho capito dove devo fare la new DBContext, in RegisterServices di ninject?
Modificato da Davide_Sangalli il 18 febbraio 2012 03.19 -
5.610 messaggi dal 09 febbraio 2002
Contributi
ciao,

Davide_Sangalli ha scritto:

non ho capito dove devo fare la new DBContext,

Non devi :) Ci pensa Ninject a crearti le istanze del DBContext e dei repository. Idealmente, non dovrai mai più usare la parola chiave new, ma sarà Ninject a darti le istanze.
Riprendiamo l'esempio di questo repository:
public class ClienteRepository : IClienteRepository {
  public ClienteRepository(MioDbContext contesto){...}
}
Vedi che non ha costruttori senza parametri, ma ha un solo costruttore che accetta un MioDbContext. Disegnando il repository così, esponi correttamente la sua dipendenza da un MioDbContext. Cioè, rendi evidente che ne ha bisogno per poter funzionare, un po' come una lavatrice a gettoni che se non ci metti prima dentro soldi e detersivo non potrà erogare il servizio (<- "lavare").

Tu devi soltanto aggiungere i bindings nella funzione RegisterServices.
kernel.Bind<IClienteRepository>().To<ClienteRepository>();
kernel.Bind<MioDbContext>().ToSelf().InRequestScope();
Come dicevo nel post precedente, il metodo .InRequestScope() farà in modo che il MioDbContext iniettato nei vari repository sarà sempre lo stesso (almeno finché si resta all'interno della stessa richiesta web), consentendoti così di realizzare il pattern Unit of Work.

Ora il repository e i suoi contesti non resta che usarli. Come ottenere un riferimento ad essi? Potresti farteli dare direttamente da Ninject, usando il metodo .Get<T>() del kernel ma siccome immagino che lo stai usando come DependencyResolver di MVC3, puoi sfruttare la stessa tecnica che abbiamo visto prima, ovvero creare un costruttore nel tuo Controller che accetti come parametri tutto quello che ti serve per lavorare.

public class ClienteController : Controller
    {
        MioDbContext _contesto;
        IClienteRepository _repoCliente;

        //questo è il costruttore del tuo controller
        //contesto e repository ti vengono passati da ninject, non devi più usare new!
        public ClienteController(MioDbContext contesto, IClienteRepository repoCliente)
        {
            _contesto = contesto;
            _repoCliente = repoCliente;
        }

        //questa è una tua ipotetica action "Create"
        [HttpPost]
        public ActionResult Create(Cliente cliente)
        {
            //uso la referenza al repository per aggiungere il cliente
            _repoCliente.Add(cliente);
            //salvo il contesto
            _contesto.SaveChanges();            
        }
}
Ora, questo che vedi è un esempio banale che non si avvicina al tuo caso reale, ma è solo per dimostrare come Ninject possa iniettare istanze nei costruttori.

EDIT: negli esempi ho usato l'implementazione concreta del contesto (MioDbContext), forse incorrettamente, infatti avrei dovuto astrarlo usando la sua classe base (DBContext), o un'interfaccia. Dipende da cosa devi realizzare.

ciao
Modificato da BrightSoul il 18 febbraio 2012 15.05 -

- So what you're saying is, if we get in trouble, there's no one to help us out?
- I'm afraid not.
- Fantastic!
24 messaggi dal 10 aprile 2003
funziona quasi tutto, l'unico problema e che se nella stessa richiesta provo ad inserire 1 UN SOLO oggetto della classe2 alla lista sulla classe1 non mi crea problemi, se provo ad inserirne 2 mi torna un errore su ObjectStateManager dicendomi che esiste già la chiave.
L'unico modo è ricaricare l'oggetto esistente,ripassargli ogni singolo campo e aggiungere i nuovi oggetti nella lista.
E' normale?
5.610 messaggi dal 09 febbraio 2002
Contributi
ciao,
l'errore che ottieni può verificarsi ad esempio quando fai l'.Attach di due nuovi oggetti. Appena istanziati, entrambi hanno lo stesso valore predefinito per la loro proprietà .ID e quindi il contesto non può accomodare il secondo .Attach perché si troverebbe due istanze diverse con la stessa chiave.

La stessa cosa non si verifica invece se fai .Add(). Il contesto sa che si tratta di un nuovo oggetto e quindi "non bada" al valore della proprietà .ID perché sa che dovrà andarsela a leggere dal DB subito dopo aver eseguito il comando INSERT.

Se questa indicazione non dovesse aiutarti, posta un po' codice.
ciao

- So what you're saying is, if we get in trouble, there's no one to help us out?
- I'm afraid not.
- Fantastic!

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.
Community
Ultimi messaggi
UTENTI ONLINE
In primo piano

I più letti di oggi

Media
In evidenza
MISC