2010-01-18 12 views
6

Sto riscrivendo una libreria C# in F # in cui la maggior parte delle classi esegue il mapping one-to-one con le tabelle del database (simile a ActiveRecord). Sto valutando se utilizzare record o classi (forse anche DU?). C'è una buona dose di convalida nei setter per mantenere invarianti. Quale sarebbe il modo migliore per modellare questo in F #? Non desidero che un oggetto che vìola la logica aziendale venga mantenuto nel database. Tutte le idee sono benvenute.Record di modellazione del database come tipi

Alcuni pensieri aggiuntivi ... È meglio spostare gli invarianti in una classe 'controller' esterna? Provenendo da C#, è sbagliato consentire a un oggetto che corrisponde a un record del database di contenere tutto ciò che non può essere salvato nel database. Suppongo perché fallire prima sembra meglio che fallire più tardi.

+0

Qualcuno può suggerire un approccio più 'funzionali'(o semplicemente diverso)? – Daniel

risposta

2

Questo dovrebbe essere un buon modo per gestirlo. Avere la tua logica di validazione nel costruttore ti darà un pezzo di mente più avanti nel tuo codice perché l'oggetto è immutabile. Questo apre anche possibilità multi-threading.

Immutabile Versione

type Customer (id, name) = 

    do // Constructor 
     if id <= 0 then 
      raise(new ArgumentException("Invalid ID.", "id")) 
     elif String.IsNullOrEmpty(name) then 
      raise(new ArgumentException("Invalid Name.", "name"))  

    member this.ID 
     with get() = id 
    member this.Name 
     with get() = name 

    member this.ModifyName value = 
     new Customer(id, value)  

Mutevole Versione

type Customer (id) = 

    let mutable name = "" 

    do // Constructor 
     if id <= 0 then 
      raise(new ArgumentException("Invalid ID.", "id")) 

    member this.ID 
     with get() = id 
    member this.Name 
     with get() = name 
     and set value = 
      if String.IsNullOrEmpty(name) then 
       raise(new ArgumentException("Invalid Name.", "value")) 
      name <- value 
+0

La maggior parte delle operazioni su questi tipi sono nel formato: caricamento, modifica, salvataggio. A parte avere la semantica della copia (come i record) per le classi, sembra che il tipo sia mutabile e che abbia la logica di validazione nei setter della proprietà. – Daniel

+0

Quindi in pratica copia quello che ho in C#? – Daniel

+0

Sì, non si vuole veramente separare la convalida dall'oggetto. – ChaosPandion

3

Si possono avere i vostri dati in un record, e ancora mantenere la logica di convalida con il tipo di dati, collegando metodi per il record:

type Person = 
    { First : string; 
     Last : string; } with 
    member x.IsValid() = 
     let hasValue = System.String.IsNullOrEmpty >> not  
     hasValue x.First && hasValue x.Last 

let jeff = { First = "Jeff"; Last = "Goldblum" } 
let jerry = { jeff with First = "Jerry" } 
let broken = { jerry with Last = "" } 

let valid = [jeff; jerry; broken] 
      |> List.filter (fun x -> x.IsValid()) 

La semantica della copia per i record è quasi altrettanto comoda di una proprietà. La convalida non avviene sul set di proprietà, ma è facile filtrare un elenco di record fino a solo quelli validi.

+0

Questo approccio è molto naturale in F #, ma ho difficoltà a evitare la pulizia delle classi completamente incapsulate. Forse non c'è una soluzione best-of-both-worlds. Sto solo esplorando le opzioni. – Daniel

+0

Dovresti davvero attaccarti ai bei oggetti incapsulati. – ChaosPandion

0

Hai dato un'occhiata al mio progetto FunctionalNHibernate? È progettato come un livello sopra Nhibernate per consentire di mappare in modo dichiarativo i record su un database. E 'ancora presto, ma si tratta solo di utilizzabile: http://bitbucket.org/robertpi/functionalnhibernate/

+0

In realtà ho. Mi sono iscritto al gruppo Google e ho tenuto d'occhio i progressi. Ma dal momento che non ho alcuna esperienza con NHibernate, e ho già un ORM che ho scritto in C# (che sono in fase di conversione), sono stato riluttante a passare a un altro ORM. – Daniel

+0

Inoltre, mi chiedo da quando è stato scritto NHibernate per C#, una versione F # riuscirà a sfruttare i vantaggi della programmazione funzionale?Mi piacerebbe vedere un ORM progettato dal basso verso l'alto da una prospettiva funzionale ... che si spera possa chiudere il RDBMS/mancata corrispondenza dell'impedenza di programmazione funzionale il più possibile. – Daniel

+0

Una riscrittura da zero sarebbe l'ideale, ma dal mio punto di vista NHibernate fornisce già alcune interessanti funzionalità per l'astrazione dell'RDBMS, che ritengo sia molto dispendioso in termini di tempo per riscrivere da zero. In altre parole, non credo che sarete in grado di utilizzare tutto l'NH, ma sarete in grado di usarne abbastanza per farne la pena. – Robert

Problemi correlati