2010-01-18 8 views
6

Estoy reescribiendo una biblioteca C# en F # en la que la mayoría de las clases se correlacionan individualmente con las tablas de la base de datos (similar a ActiveRecord). Estoy considerando si usar registros o clases (¿incluso DU?). Hay una buena cantidad de validación en los establecedores de propiedades para mantener invariantes. ¿Cuál sería la mejor manera de modelar esto en F #? No quiero que persista en la base de datos un objeto que infringe la lógica comercial. Cualquier idea es bienvenida.Modelado de registros de bases de datos como tipos

Algunas consideraciones adicionales ... ¿Es mejor mover las invariantes a una clase externa de "controlador"? Viniendo de C#, se siente mal permitir que un objeto que corresponde a un registro de la base de datos contenga cualquier cosa que no se pueda guardar en la base de datos. Supongo que porque fallar antes parece mejor que fracasar más tarde.

+0

¿Alguien puede sugerir un enfoque más 'funcional' (o simplemente diferente)? – Daniel

Respuesta

2

Esto debería ser una buena forma de manejarlo. Tener su lógica de validación en el constructor le dará tranquilidad luego en su código porque el objeto es inmutable. Esto también abre posibilidades multihilo.

Inmutable Versión

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)  

mutable Versión

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 mayoría de las operaciones en estos tipos tienen la forma: cargar, modificar, guardar. A falta de tener semántica de copia (como registros) para las clases, parece que requiere que el tipo sea mutable y que tenga la lógica de validación en los establecedores de propiedades. – Daniel

+0

¿Entonces básicamente copia lo que tengo en C#? – Daniel

+0

Sí, realmente no desea separar la validación del objeto. – ChaosPandion

3

Usted puede tener sus datos en un registro, y aún así mantener la lógica de validación con el tipo de datos, adjuntando los métodos a el registro:

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 semántica de copia para los registros es casi tan conveniente como establecer una propiedad. La validación no ocurre en el conjunto de propiedades, pero es fácil filtrar una lista de registros solo a los válidos.

+0

Este enfoque se siente muy natural en F #, pero me cuesta mucho abandonar la limpieza de las clases totalmente encapsuladas. Tal vez no hay una mejor solución para ambos mundos. Solo estoy explorando las opciones. – Daniel

+0

Deberías quedarte con los simpáticos objetos encapsulados. – ChaosPandion

0

¿Has echado un vistazo a mi proyecto FunctionalNHibernate? Está diseñado como una capa en la parte superior de nhibernate para permitirle asignar mapas declarativamente a una base de datos. Es pronto, pero es útil: http://bitbucket.org/robertpi/functionalnhibernate/

+0

Tengo en realidad. Me uní al Grupo de Google y he estado pendiente del progreso. Pero dado que no tengo ninguna experiencia con NHibernate, y ya tengo un ORM que escribí en C# (que estoy en proceso de conversión), me he mostrado reacio a realizar un cambio completo a otro ORM. – Daniel

+0

Además, me pregunto que dado que NHibernate fue escrito para C#, ¿una versión F # explotará cualquiera de los beneficios de la programación funcional?Me gustaría ver un ORM diseñado desde cero desde una perspectiva funcional ... que, con suerte, cerraría tanto como fuera posible la impedancia de RDBMS/impedancia de programación funcional. – Daniel

+0

Una reescritura desde cero sería ideal, pero desde mi punto de vista, NHibernate ya ofrece algunas características interesantes para abstraer el RDBMS que utilizas y que creo que llevaría mucho tiempo reescribir desde cero. O dicho de otra manera, no creo que puedas usar todo el NH, pero podrás usar lo suficiente para que valga la pena. – Robert

Cuestiones relacionadas