Come popolare l'oggetto Lazy dal database

6

Ho queste classi:

public class Order
{
    private Lazy<IEnumerable<Volume>> _volumes;
    long ID { get; private set; }
    string Description { get; private set; }
    IEnumerable<Volume> Volumes { get { return _volumes.Value; } }
    //etc..
}
public class Volume
{
    long ID { get; private set; }
    string Description { get; private set; }
    //etc..
} 

Ho bisogno di istanziare e popolare più ordini. Per fornire gli oggetti di queste classi ho questi repository:

public interface IOrderRepository
{
    Order GetByID(long ID);
    IEnumerable<Order> GetAll();
    Order Create(long ID, string Description);
    void Update(Order O);
    void Delete(Order O);
}
public interface IVolumeRepository
{
    Volume GetByID(long ID);
    IEnumerable<Volume> GetAll(Order O);
    Volume Create(long ID, string Description, Order O);
    void Update(Volume V);
    void Delete(Volume V);
}

Non ho bisogno di compilare i volumi di ciascun ordine al momento dell'istanziazione, sarebbe meglio implementare il caricamento lento, secondo me, poiché possono esserci molti volumi.
Quindi, come faccio a far sapere all'Ordine dove recuperare i volumi? Ho questo codice che popola l'ordine che viene istanziato:

//Interface
public interface IVolumeFetcher { IEnumerable<Volume> GetAll(Order O); }
//Order Constructor
public Order(long ID, string Description, IVolumeFetcher VF)
{
    _volumes = new Lazy<IEnumerable<Volume>>(() => VF.GetAll(this));
}

Questo dà all'Ordine un riferimento al Deposito, non mi sembra una buona idea.
Potrei mantenere i volumi dell'ordine in una lista semplice e riempirla quando necessario:

public List<Volume> Volumes { get; private set; }

Ma questo approccio sarebbe facilmente corrotto, qualsiasi chiamante potrebbe aggiungere un volume alla lista e non sarebbe mantenuto nel DB. Btw, questa è un'applicazione a tre livelli, con una classe Order e Volume per ogni livello, oltre a un repository.

    
posta Tea With Cookies 23.09.2015 - 16:36
fonte

2 risposte

1

Supponendo script di transazione sugli oggetti e senza ORM.

Non vuoi che il tuo oggetto abbia un codice di repository. Tratta Lazy<T> come faresti con qualsiasi parametro del costruttore, quindi IOrderRepository sarà responsabile di fornirlo come un oggetto costruito al costruttore dell'Ordine.

public Order(long id, string description, Lazy<IEnumerable<Volume>> volumes)
{
    ...
    _volumes = volumes;
}

Se si è preoccupati del riferimento al repository che si trova nella chiusura di Lazy<T> o che deve essere eliminato, poiché questo utilizzo è di sola lettura, è possibile creare ed eliminare un IVolumeRepository all'interno del metodo Lazy:

// assuming IVolumeRepository is IDisposable or UOW
var volumes = new Lazy<IEnumerable<Volume>>(() =>
{
    //using (var repo = new ConcreteVolumeRepository())
    // or repo factory
    //using (var repo = volumeRepoFactoryFn())
    // or DI container
    using (var repo = DIContainer.Get<IVolumeRepository>())
    {
        return VF.GetAll(orderId))
    }
};

var order = new Order(orderId, description, volumes)

Se il tuo repository è un singleton (non che dovrebbe essere), allora vorrei solo fare:

//IVolumeRepository volumeRepo ...
var orderId = ...
var description = ...
var volumes = new Lazy<IEnumerable<Volume>>(() => volumeRepo.GetAll(orderId));

var order = new Order(orderId, description, volumes);

Come nota a margine, il tuo repository di volume dovrebbe caricare l'ID ordine piuttosto che l'ordine stesso. Presumo che il metodo IVolumeRepository.GetAll(Order O) tenga semplicemente la proprietà ID dall'ordine, che non è utile per astrarre. Se vuoi assicurarti che si tratti di un ID di un Ordine (rispetto a qualsiasi altro tipo di lungo), puoi rendere OrderId una classe o una struttura separata che avvolge a lungo. Ciò avrebbe lo stesso scopo senza causare un problema di uovo di gallina con il caricamento di volumi. Ma suppongo che i test unitari dovrebbero fornire una verifica sufficiente senza dover creare una struttura OrderId separata. (Perché altrimenti useresti le interfacce del repository se non al test unitario?)

    
risposta data 24.09.2015 - 22:13
fonte
0

Sto bene con Order avendo come riferimento IVolumeRepository , ma solo in 2 condizioni.

Primo: tutte le entità coinvolte sono sotto il singolo Context . Per esempio. esiste una classe che rappresenta la transazione corrente che gestisce la durata di tutte le sue entità. Quindi questo Contesto deve esistere finché si manipolano quelle entità e le entità appena recuperate e create rientrano in questo contesto. Ecco come fanno gli ORM.

Il secondo è che l'implementazione di IVolumeRepository viene iniettata in modo trasparente quando la nuova istanza di Order viene creata o materializzata dal database. Ciò garantisce che il dominio non abbia alcuna conoscenza sull'effettiva implementazione del repository. Di nuovo, questo è il modo in cui gli ORM lo fanno, perché ogni istanza di entità materializzata (gli ORM creano per lo più la propria classe concreta per ogni entità attraverso la generazione del codice di runtime) ha fatto riferimento a Context .

    
risposta data 26.10.2015 - 08:58
fonte

Leggi altre domande sui tag