Relazione degli oggetti di modellazione

0

Sto cercando di capire un modello generale. Supponiamo che io abbia un'applicazione in cui mostro User e tutte le voci Jobs in cui ha applicato, qui User e Job sono many2many relazione. Nella stessa interfaccia ho bisogno di mostrare tutto il Address della percentuale di accesso% co_de.

Quindi avrò le seguenti classi:

class User {
  List<Address> address = null;
  List<Job> jobs = null;

  public List<Job> getJobs() {

  }

  public List<Address> getAddress() {

  }
}

In alto, suppongo che per ottenere sia i lavori sia l'indirizzo devo prima ottenere l'istanza utente che di per sé richiede una chiamata al database.

Quindi, posso recuperare tutte le informazioni contemporaneamente tramite join e poi inviarle al client o posso optare per il caricamento pigro dei dati quando richiesto, così, se c'è una scheda separata per i lavori, posso richiedere i lavori ma Ho bisogno di creare prima un'istanza dell'utente e la chiamata User che renderebbe internamente DB chiamata per il recupero dei lavori, quindi nel complesso ci saranno due chiamate al database per il recupero di ogni oggetto correlato che mi sembra un sovraccarico.

Beh, la mia vera preoccupazione è che i dati debbano venire attraverso un database che non conosce nulla dei miei oggetti e viceversa, come risolvere questo dilemma?

    
posta vivek 19.03.2017 - 07:36
fonte

3 risposte

2
  • Inizia con l'implementazione più semplice a cui puoi pensare, senza investire troppo a pensare a "troppe chiamate al database". Ad esempio, implementa qualcosa senza il lazy loading e tre chiamate db (seleziona da Utente, seleziona da Lavori, seleziona da Indirizzo).

  • Quindi, usa questo nel tuo programma e prova se è abbastanza veloce per i tuoi purporses. Se ciò va bene, non sprecare il tuo tempo ottimizzandolo di più.

  • Tuttavia, se questa soluzione risulta non essere abbastanza veloce, è possibile aggiungere ulteriori ottimizzazioni in seguito. Queste ottimizzazioni dovrebbero adattarsi ai tuoi casi d'uso. Ad esempio, se il collo di bottiglia è un caso di utilizzo in cui vengono recuperati molti utenti senza la necessità di lavori e indirizzi, i processi di caricamento e gli indirizzi "on demand" possono essere una buona soluzione.

  • Se hai altri casi di utilizzo in cui spesso hai bisogno degli utenti insieme ai loro lavori e indirizzi, puoi fornire un'implementazione di caricamento ottimizzata aggiuntiva, ottenendo questi dati da un join complesso in una query. In questo caso, è necessario progettare l'interfaccia di recupero in un modo che il chiamante possa controllare per caricare un utente insieme a tutti gli indirizzi e i lavori "precaricati" o meno (quindi i lavori e gli indirizzi verranno caricati solo "su richiesta") .

Il codice risultante non è più ASCIUTTO, perché ora hai una logica di caricamento equivalente implementata due volte, utilizzando diversi metodi di query. Ma ciò è inevitabile: l'ottimizzazione è spesso un compromesso tra manutenibilità o velocità, quindi non ottimizzare senza necessità reali.

    
risposta data 19.03.2017 - 14:23
fonte
0

Considera di scrivere classi separate Repository che sono responsabili per l'interrogazione del tuo database, ma che non contengono nemmeno dati di dominio. (Potrebbero contenere lo stato della connessione DB o qualcosa di simile ma non dati di dominio effettivi)

Quando si lavora con i risultati della query, la soluzione ideale è quella di mappare su semplici entità "modello" che contengono solo proprietà e nessuna logica (cioè non considerano le entità mappate come oggetti, perché la loro responsabilità è solo quella di colmare il divario per il tuo database).

Considera di modificare User in UserModel che contiene solo le proprietà dati mappate dal tuo database e nessuna logica. (considera anche Job a JobModel per coerenza)

In secondo luogo, utilizza diverse classi Repository per interrogare il database e restituire i dati mappati alle classi di entità; Ad esempio

  • UserRepository per interrogare e mappare UserModel dati
  • JobRepository per interrogare e mappare JobModel dati
  • AddressRepository per interrogare e mappare AddressModel dati

Ciascuna delle tue visualizzazioni dell'interfaccia utente può scegliere i dati di cui hanno bisogno da ciascun repository (se ce ne sono) in base a una query decisa dal controller della vista, senza collocare una dipendenza su un oggetto User .

Infine, se una vista ha bisogno di qualcosa di più di un singolo modello di database (e soprattutto se ha bisogno di dati aggiuntivi che non provengono dal database), considera di fare in modo che il View Controller costruisca ViewModel s in base ai modelli dei tuoi repository . Ad esempio:

class UserViewModel {
    UserModel user;
    List<AddressModel> addresses;
    bool isReadOnly;
}

I ViewModel sono utili per garantire che ogni View abbia i dati giusti (e solo i dati di cui ha bisogno) senza lasciare problemi di interfaccia utente nel resto di un'applicazione. Modelli di interfaccia utente comuni come MVC / MVP utilizzano ViewModels per disaccoppiare qualsiasi struttura di interfaccia utente speciale o strutture di interfaccia utente dal resto dell'app

Aggiornamento:

(In risposta al commento sulla logica aziendale)

Né le classi dell'interfaccia utente né le classi di database / persistenza dovrebbero occuparsi della logica aziendale. La maggior parte delle applicazioni non banali richiede molto più della semplice capacità di estrarre dati direttamente da un repository; un "livello" in più tra le classi e le funzioni che contengono quella logica è la soluzione tipica.

La logica aziendale, la logica delle app e altre classi intermedie verrebbero utilizzate direttamente dalle classi del controller UI, ad esempio (Rough schematic):

 View --> Controller --> Business logic classes --> Repositories / External APIs / etc.

Frecce che indicano la direzione di ciascuna dipendenza. Un controller di visualizzazione può dipendere da classi contenenti la logica aziendale ma non viceversa; Le classi di business logic possono dipendere dai repository ma i repository non saprebbero ancora nulla della logica di business.

    
risposta data 19.03.2017 - 11:41
fonte
0

Il problema chiave

Non puoi disgiungere List<Address> address e List<Job> jobs da class User

Crea classi personalizzate per abilitare il disaccoppiamento

Queste classi di stile DSL possono essere istanziate in modo indipendente perché dispongono di funzionalità appropriate in modo che la classe User non operi più come queste classi mancanti.

public class UserAddresses {
   protected int UserId { get; set; }
   public List<Address> Addresses { get; protected set; }

   public UserAddresses ( int UserId, List<Address> myAddresses = null ) { }
}

public class UserAppliedJobs {
   protected in UserID { get; set; }
   public List<Job> AppliedJobs { get; protected set; }

   public UserAppliedJobs ( int userId, List<Job> myJobHopes = null ) { }
}

Queste classi avranno i metodi Add , Remove , Find . Probabilmente dovrebbero avere iteratori, IEnumerable , IEnumerator implementazioni. Quindi qualsiasi altra funzione che li rende UserAddresses / UserAppliedJobs di fronte a qualsiasi altro tipo nel tuo modello di business.

Immagino di sovrascrivere Equals per "uguaglianza di istanza" - basato su userId; assumendo sempre una sola raccolta per utente.

    
risposta data 19.03.2017 - 20:49
fonte