2009-03-13 11 views
15

Sto cercando di capire il modo più pulito per farlo.Miglior "modello" per il livello di accesso ai dati per l'oggetto aziendale

Attualmente ho un oggetto cliente:

public class Customer 
{ 
    public int Id {get;set;} 
    public string name {get;set;} 
    public List<Email> emailCollection {get;set} 
    public Customer(int id) 
    { 
     this.emailCollection = getEmails(id); 
    } 
} 

Allora il mio oggetto e-mail è anche piuttosto semplice.

public class Email 
{ 
    private int index; 
    public string emailAddress{get;set;} 
    public int emailType{get;set;} 
    public Email(...){...} 
    public static List<Email> getEmails(int id) 
    { 
     return DataAccessLayer.getCustomerEmailsByID(id); 
    } 
} 

Il DataAccessLayer attualmente si collega alla base di dati, e utilizza uno SqlDataReader per scorrere il set di risultati e crea nuovi oggetti e-mail e li aggiunge a un elenco che restituisce quando fatto.

Quindi dove e come posso migliorare?

Se il mio DataAccessLayer dovrò restituire un DataTable e lasciare l'oggetto Email da analizzare e restituire un Elenco al Cliente?

Immagino che "Fabbrica" ​​sia probabilmente la parola sbagliata, ma dovrei avere un altro tipo di EmailFactory che prende un DataTable dal DataAccessLayer e restituisce un Elenco all'oggetto Email? Immagino che quel tipo di suoni sia ridondante ...

E 'forse una pratica corretta avere il mio email.getEmails (id) come metodo statico?

Potrei semplicemente buttarmi fuori cercando di trovare e applicare il miglior "schema" a quello che normalmente sarebbe un compito semplice.

Grazie.


Follow-up

ho creato un esempio di lavoro in cui il mio dominio/Business Object estrae un record di un cliente da id da un database esistente. I file di mappatura xml in nhibernate sono davvero accurati. Dopo aver seguito un tutorial per configurare le sessioni e le fabbriche del repository, il pull dei record del database era abbastanza semplice.

Tuttavia, ho notato un enorme successo in termini di prestazioni.

Il mio metodo originale consisteva in una stored procedure sul DB, chiamata da un oggetto DAL, che analizzava il set di risultati nel mio dominio/oggetto commerciale.

Ho eseguito il clock del mio metodo originale a 30 ms per acquisire una singola registrazione cliente. Ho quindi sincronizzato il metodo Nhibernate con 3000ms per catturare lo stesso record.

Mi manca qualcosa? O ci sono solo un sacco di spese generali con questa rotta di divieto?

Altrimenti mi piace la pulizia del codice:

protected void Page_Load(object sender, EventArgs e) 
{ 
    ICustomerRepository repository = new CustomerRepository(); 
    Customer customer = repository.GetById(id); 
} 

public class CustomerRepository : ICustomerRepository 
     { 
      public Customer GetById(string Id) 
      { 
       using (ISession session = NHibernateHelper.OpenSession()) 
       { 
        Customer customer = session 
             .CreateCriteria(typeof(Customer)) 
             .Add(Restrictions.Eq("ID", Id)) 
             .UniqueResult<Customer>(); 
        return customer; 
       } 
      } 
     } 

Il example I followed mi aveva creare una classe di supporto per aiutare a gestire la sessione, forse è per questo sto ottenendo questo overhead?

public class NHibernateHelper 
    { 
     private static ISessionFactory _sessionFactory; 
     private static ISessionFactory SessionFactory 
     { 
      get 
      { 
       if (_sessionFactory == null) 
       { 
        Configuration cfg = new Configuration(); 
        cfg.Configure(); 
        cfg.AddAssembly(typeof(Customer).Assembly); 
        _sessionFactory = cfg.BuildSessionFactory(); 
       } 
       return _sessionFactory; 
      } 

     } 

     public static ISession OpenSession() 
     { 
      return SessionFactory.OpenSession(); 
     } 
    } 

Con l'applicazione su cui sto lavorando, la velocità è essenziale. E alla fine passeranno molti dati tra l'app web e il database. Se impiega un agente 1/3 di secondo per ottenere un record del cliente rispetto a 3 secondi, questo sarebbe un grande successo.Ma se sto facendo qualcosa di strano e questo è un costo di installazione iniziale di una volta, allora potrebbe valerne la pena se le prestazioni fossero altrettanto buone dell'esecuzione di stored procedure sul DB.

Ancora aperto ai suggerimenti!


Aggiornato.

Sto rottamando la mia rotta ORM/NHibernate. Ho trovato che le prestazioni sono troppo lente per giustificare l'utilizzo. Le richieste di base dei clienti richiedono troppo tempo per il nostro ambiente. 3 secondi rispetto alle risposte inferiori al secondo è troppo.

Se volessimo query lente, terremmo la nostra attuale implementazione. L'idea di riscriverlo era di aumentare drasticamente i tempi.

Tuttavia, dopo aver giocato con NHibernate la scorsa settimana, è un ottimo strumento! Semplicemente non si adatta alle mie esigenze per questo progetto.

+0

Barry- Sì, funziona benissimo come è adesso. L'unica cosa che posso pensare è che il mio DataAccessLayer restituisca un DataTable, in modo da poter eseguire controlli di convalida nel mio Business Layer (ad es. Oggetto Email) invece che nel livello di accesso ai dati. –

+1

L'esempio che hai pubblicato è il classico "modello di dominio anemico". Sulla base del tuo esempio non hai nemmeno bisogno di un oggetto business. Un oggetto aziendale dovrebbe mantenere la logica aziendale e il tuo no. –

risposta

6

Se la configurazione che hai funziona ora, perché scherzare? Non sembra che tu stia identificando particolari esigenze o problemi con il codice così com'è.

Sono sicuro che un gruppo di tipi OO potrebbe riunirsi intorno e suggerire vari rifacimenti qui in modo che vengano rispettate le responsabilità e i ruoli corretti, e qualcuno potrebbe anche provare a calzare in un modello o due di progettazione. Ma il codice che hai ora è semplice e sembra che non abbia problemi - direi di lasciarlo.

+0

Mi considero un ragazzo OO, ma sono pienamente d'accordo. L'attuale soluzione è così semplice che posso capirlo anche io, che è sicuramente una buona qualità! – Treb

+2

Un suggerimento è aggiungere altro comportamento "aziendale" all'oggetto business. Sembra che l'oggetto business non venga usato correttamente sopra. –

5

Ho implementato un livello DAL facendo fondamentalmente ciò che fa NHibernate ma manualmente. Ciò che NHibernate fa è creare una classe Proxy che erediti dal tuo oggetto Dominio (che dovrebbe avere tutti i suoi campi contrassegnati come virtuali). Tutto il codice di accesso ai dati va nelle sostituzioni delle proprietà, in realtà è piuttosto elegante.

Ho semplificato questo aspetto facendo in modo che i miei repository riempissero le stesse proprietà e usassero solo un proxy per il caricamento Lazy. Quello che ho finito è un insieme di classi in questo modo:

public class Product { 
    public int Id {get; set;} 
    public int CustomerId { get; set;} 
    public virtual Customer Customer { get; set;} 
} 
public class ProductLazyLoadProxy { 
    ICustomerRepository _customerRepository; 
    public ProductLazyLoadProxy(ICustomerRepository customerRepository) { 
    _customerRepository = customerRepository; 
    } 
    public override Customer { 
    get { 
     if(base.Customer == null) 
     Customer = _customerRepository.Get(CustomerId); 
     return base.Customer 
    } 
    set { base.Customer = value; } 
    } 
} 
public class ProductRepository : IProductRepository { 
    public Product Get(int id) { 
    var dr = GetDataReaderForId(id); 
    return new ProductLazyLoadProxy() { 
     Id = Convert.ToInt(dr["id"]), 
     CustomerId = Convert.ToInt(dr["customer_id"]), 
    } 
    } 
} 

Ma dopo aver scritto circa 20 di questi ho appena rinunciato e ha imparato NHibernate, con Linq2NHibernate per l'interrogazione e FluentNHibernate per la configurazione al giorno d'oggi i blocchi stradali sono più bassi che mai.

2

Questo potrebbe essere troppo radicale per te e in realtà non risolve la domanda, ma che ne dici di rastrellare completamente il tuo livello dati e optare per un ORM? Risparmierai un sacco di ridondanza del codice che porterà una spesa di circa una settimana su un DAL.

A parte questo, lo schema che si utilizza assomiglia a un modello di repository, una specie di. Direi che le tue opzioni sono

  • Un oggetto servizio nella classe di posta elettronica, ad esempio EmailService, istanziato nel costruttore o in una proprietà. Accessibile tramite un caso, come email.Service.GetById (id)
  • Procedimento statico mail, come Email.GetById (id) che è un approccio simile
  • Una classe statica completamente separato che è fondamentalmente una classe facciata, EmailManager ad esempio, con metodi statici come EmailManager.GetById (int)
  • Il pattern ActiveRecord in cui si ha a che fare con un'istanza, ad esempio email.Save() ed e-mail.GetById()
2

Molto probabilmente l'applicazione ha la sua configurazione logica di dominio in transaction scripts. Per le implementazioni .NET che utilizzano lo script delle transazioni, Martin Fowler raccomanda l'utilizzo del modello table data gateway. .NET offre un valido supporto per questo modello poiché il pattern del gateway di dati della tabella è ottimo con record set, che Microsoft implementa con le classi di tipo DataSet.

Vari strumenti all'interno dell'ambiente di Visual Studio dovrebbero aumentare la produttività. Il fatto che DataSet possa essere facilmente associato a vari controlli (come il DataGridView) lo rende una buona scelta per le applicazioni basate sui dati.

Se la logica aziendale è più complessa di alcune convalide, lo domain model diventa una buona opzione. Si noti che un modello di dominio viene fornito con un insieme diverso di requisiti di accesso ai dati!

Problemi correlati