Dove popolare gli oggetti

1

Come menzionato in questa domanda , I sto spostando la nostra squadra verso gli oggetti (al contrario del semplice lancio di DataTable e variabili ovunque). Ho scelto un punto adatto per il progetto che contiene le definizioni dell'oggetto, ma non sono sicuro di come dovrei andare a popolare alcuni degli oggetti. In particolare, cosa faccio con le classi come proprietà?

Public Class Class1
    Public Property SomeProperty As String
    Public Property SomeOtherProperty As String
    Public Property SomeKey As Integer
    Public Property Foo As Class2
End Class

In questo esempio di base, posso facilmente popolare le prime tre proprietà da una query, ma Foo ha il proprio insieme di proprietà. In questo momento, per creare un List(Of Class1) , generi i dati per tutti gli oggetti Class1, quindi uso SomeKey per tornare indietro e, un oggetto alla volta, popola tutto il Foo . Certamente funziona, ma nel mio caso è piuttosto lento, e sembra che forse sto semplicemente sbagliando.

Sto gestendolo in modo errato? Se sì, cosa dovrei fare? L'unica altra cosa che posso venire è creare una query (o stored procedure) che restituisca tutti i dati appropriati per tutti gli oggetti. Nel mio caso di test si tratta di un elenco che contiene il 154% diClass1, con ciascuno di essi con quattro proprietà come Foo , e alcuni di quelli che hanno classi come proprietà.

    
posta Dave Johnson 09.03.2014 - 17:01
fonte

3 risposte

2

Il tuo approccio attuale causa quello che viene chiamato come N + 1 Seleziona problema (vedi link ).

Un modo per risolverlo è recuperare tutti i dati richiesti nella query usando seleziona e left join distinti. Questo è chiamato avido recupero . Nella maggior parte dei casi, è la soluzione preferita. Se hai una gerarchia profonda, potresti voler creare metodi di ricerca separati nella classe del tuo repository, ad esempio findStudent() popolerà solo Student e findStudentForReview() restituirà Student.subjects.assignments .

Un altro modo per risolverlo è creare un getter per la proprietà Foo che recupera i dati per Class2 se i dati non sono stati recuperati prima. Questo è chiamato approccio lazy fetching : la query per Class2 verrà eseguita solo quando è necessario il valore Foo .

Oppure, potresti usare un framework ORM per la tua piattaforma. Avrai bisogno di ulteriori investimenti qui. Il vantaggio è che il framework ORM gestirà la popolazione di dati e fornirà oggetti pronti per l'uso.

    
risposta data 10.03.2014 - 20:19
fonte
4

Non esiste una "best practice" su come "popolare gli oggetti", allo stesso modo in cui non esiste una best practice per come creare / popolare una stringa o un intero da qualche parte nel programma. Gli oggetti sono istanze di classi, che possono essere viste come equivalenza di un tipo definito dall'utente. Crei e utilizzi alcuni di essi in un ambito di un piccolo blocco, alcuni di essi hanno un ambito di funzione, alcuni di essi nell'ambito di una classe, un ambito del modulo o un ambito globale, purché sia necessaria l'istanza di singoli oggetti nel programma per risolvere un certo compito. Quale attività è, e quale durata per un oggetto è appropriato, dipende completamente da come la classe che hai creato, le sue responsabilità e lo scenario di utilizzo.

    
risposta data 09.03.2014 - 17:14
fonte
0

Per lavorare con le entità, dovresti davvero usare Linq-to-SQL o Entity Framework. Esistono altri ORM, ma pochi ne valgono davvero la pena, non hanno nulla di reale da offrire rispetto all'EF6. Per fare ciò, devi prima creare un modello (o più modelli) delle tue origini dati, e quindi usare quel modello per interrogare l'origine dati tramite le query di Linq. L'ORM agisce come uno strato di astrazione tra il fornitore di dati e la lingua prescelta. Ad esempio, in Linq to SQL, l'oggetto di esempio verrà interrogato in questo modo:

' First you instanciate your context. This is the virtual connection to the database. You
' are actually connecting to your data model here, the connection to the database is only 
' made when there is actually a query executing.
Using db As New MyDataModel

    ' Then you define your query. Linq queries work in defered execution. They
    ' are only executed when they are actually used. The type returned is an
    ' IEnumerable(Of Class1)
    Dim c1s = From c1 In db.Class1s
              Where c1.SomeProperty = someValue
              Select c1

    ' The objects retrieved maintain their relational model as well, so accessing
    ' the Foo property is as simple as using the navigation property provided by
    ' the ORM. All of the relationships are taken care for you in the background.
    For Each c1 In c1s
        Console.WriteLine(c1.Foo.SomeProperty)
    Next

    ' Navigation properties are essentially joins, links implemented by the relationships
    ' defined in your object relational model. The following example would be this SQL:
    ' SELECT c2.* FROM Class1s c1 INNER JOIN Class2s c2 ON c1.SomeKey = c2.SomeForeignKey
    Dim c2s = From c1 In c1s Select c1.Foo

End Using

In breve non compilerai MAI il tuo oggetto come stavi descrivendo, tranne nei casi in cui hai bisogno di un output appiattito da una query, ma anche in questo caso useresti tipi anonimi.

' You can also select specific elements from a relationship through anonymous types
' Here we just define the output type as we go. This is the equivalent to selecting
' individual fields in a SQL select.
Dim anonTypeObj = (From c1 In db.Class1s
                   Select New With {.c1SomeProperty = c1.SomeProperty,
                                    .c2SomeOtherProperty = c1.Foo.SomeOtherProperty}).First

Console.WriteLine(anonTypeObj.c1SomeProperty & " : " & anonTypeObj.c2SomeOtherProperty)
    
risposta data 13.04.2014 - 11:00
fonte

Leggi altre domande sui tag