2013-01-20 25 views
8

Ho selezionato ServiceStack OrmLite per il mio progetto che è un'applicazione orientata ai dati pura. Sono disposto a consentire all'utente finale di creare i propri tipi di oggetto definiti in un formato XML che verrà utilizzato per generare classi in fase di esecuzione utilizzando CodeDOM.Aggiungi proprietà alla classe POCO in fase di esecuzione

Definirò anche alcuni oggetti "di sistema" richiesti dall'applicazione (ovvero User) ma non posso prevedere tutte le proprietà che l'utente finale utilizzerà e pertanto sto cercando un modo per consentire di estendere le classi che creo in tempo di progettazione. Esempio muggito utente

public class User 
{ 
    public Guid Uid { get; set; } 
    public String Username { get; set; } 
    public String Password { get; set; } 
} 

La fine vuole avere un Email ed un Address. Egli deve essere in grado di aggiungere le 2 proprietà alla classe superiore e tutta la classe sarà (che comunque può essere utilizzato da OrmLite, in quanto consente di sovrascrivere:

public class User 
{ 
    public Guid Uid { get; set; } 
    public String Username { get; set; } 
    public String Password { get; set; } 
    public String Email{ get; set; } 
    public String Address { get; set; } 
} 

So che ci potrebbe essere un rischio di fare quindi per arrestare il sistema (se la classe è già istanziata), quindi sto cercando il modo migliore per evitare questo problema e imitare il bisogno.

risposta

4

Sembra che ci siano due parti in quello che stai facendo qui. È necessario creare i tipi dinamicamente per supportare le proprietà aggiuntive. È inoltre necessario assicurarsi che non si finiscano mai con tipi duplicati nell'AppDomain, ad esempio due diverse definizioni di User.

tipo runtime generazione

Le varie indicazioni già fornite maniglia come creare i tipi. In un progetto, avevamo qualcosa di simile. Abbiamo creato una classe base con le proprietà principali e un dizionario per memorizzare le proprietà di "estensione". Quindi abbiamo utilizzato Reflection.Emit per creare un tipo derivato con le proprietà desiderate. Ogni definizione di proprietà viene semplicemente letta da o scritta nel dizionario nella classe base. Poiché Reflection.Emit comporta la scrittura di codice IL di basso livello, all'inizio sembra complesso. Abbiamo scritto alcune classi derivate campionarie in un'altra libreria di classi e le abbiamo compilate.Questi erano esempi di ciò che avremmo effettivamente dovuto ottenere in fase di runtime. Quindi abbiamo usato ildasm.exe per vedere quale codice ha prodotto il compilatore. Ciò ha reso abbastanza facile capire come possiamo generare lo stesso codice in fase di runtime.

evitare le collisioni namespace

La seconda sfida è quella di evitare di avere i nomi dei tipi duplicati. Abbiamo aggiunto un guid (con caratteri non validi rimossi) al nome di ciascun tipo generato per assicurarci che non sia mai successo. Difficoltà facile, anche se non so se potresti farla franca con il tuo ORM.

Se si tratta di codice server, è necessario considerare anche il fatto che gli assembly non vengono mai scaricati in .NET. Quindi, se generi ripetutamente nuovi tipi in fase di esecuzione, il tuo processo continuerà a crescere. Lo stesso accadrà nel codice client, ma potrebbe trattarsi di un problema minore se non ci si aspetta che il processo venga eseguito per un lungo periodo di tempo.

Ho detto che i gruppi non vengono scaricati; tuttavia, è possibile scaricare un intero AppDomain. Quindi, se si tratta di codice server, è possibile che l'intera operazione venga eseguita nel proprio dominio dell'app, quindi eliminarla in seguito per assicurarsi che i tipi creati dinamicamente vengano scaricati.

+0

Questo è in realtà molto vicino alla soluzione che ho trovato. Ho creato una classe 'Property' e' DataObjectType' con una relazione N <-> N. Ho quindi utilizzato il generatore di codice CodeDOM per creare un nuovo 'ExtensionAssembly' che creerà nuove classi utilizzando le proprietà di estensione delle tabelle sopra. Ho allegato ExtensionKey come guida per ciascun tipo originale utilizzato dai nuovi tipi corrispondenti come identificatore. –

+0

L'escape del conflitto di denominazione è facile come aggiungere un prefisso o un suffisso ai nuovi tipi creati, ad esempio "Utente" e "UserExtension". –

0

Perché non utilizzare una coppia di valori chiave per tutte le sue proprietà o almeno quelli dinamici?

http://msdn.microsoft.com/en-us/library/system.collections.hashtable.aspx

Puoi farlo nel modo in cui stai descrivendo con Reflection ma richiederà un risultato in termini di prestazioni, in questo modo consentirai anche la rimozione delle proprietà.

+0

perché OrmLite ha bisogno di loro come proprietà per quanto ne so. L'Htable sarà serializzato nel testo –

+0

Questo potrebbe essere d'aiuto .. http://msdn.microsoft.com/en-us/library/ms404245.aspx Si potrebbe fare una classe base e quindi usarla per creare la classe dinamica a runtime. O usi a freddo Reflection.Emit –

0

Il progetto a cui sto lavorando ha un requisito simile. Abbiamo un sistema già in produzione e disponeva di campi di aggiunta delle richieste del client.

Abbiamo risolto questo problema aggiungendo semplicemente una proprietà CustomField al nostro modello.

public class Model: IHasId<Guid> 
{ 
    [PrimaryKey] 
    [Index(Unique = true)] 
    public Guid Id { get; set; } 

    // Other Fields... 

    /// <summary> 
    /// A store of extra fields not required by the data model. 
    /// </summary> 
    public Dictionary<string, object> CustomFields { get; set; } 
} 

L'abbiamo usato per alcune settimane senza problemi.

Un ulteriore vantaggio che abbiamo riscontrato è che ogni riga poteva avere i propri campi personalizzati in modo che potessimo gestirli per record invece di richiederli per ogni record.

+0

Cosa succede se hai troppi campi e valore che il valore blobbed supererà il limite di 8000 caratteri predefinito? –

+0

Punto valido, in realtà stiamo vincolando i dati più complessi in una tabella separata a cui viene fatto riferimento da un valore id nell'elenco di CustomField. Non prevediamo che i nostri clienti richiedano un numero elevato di campi personalizzati, ma tu hai ragione, c'è il limite sul campo che deve essere preso in considerazione. –

Problemi correlati