Моделирование записей базы данных как типов - PullRequest
6 голосов
/ 19 января 2010

Я переписываю библиотеку C # на F #, в которой большинство классов отображаются один в один с таблицами базы данных (аналогично ActiveRecord). Я обдумываю, использовать ли записи или классы (может быть, даже DU?). В установщиках свойств имеется достаточное количество проверок для поддержки инвариантов. Как лучше всего смоделировать это в F #? Я не хочу, чтобы объект, который нарушает бизнес-логику, сохранялся в базе данных. Любые идеи приветствуются.

Несколько дополнительных мыслей ... Лучше ли перенести инварианты во внешний класс «контроллера»? Исходя из C #, кажется неправильным разрешать объекту, который соответствует записи базы данных, содержать что-либо, что не может быть сохранено в базе данных. Я полагаю, потому что неудача раньше кажется лучше, чем неудача позже.

Ответы [ 3 ]

3 голосов
/ 19 января 2010

Вы можете хранить свои данные в записи и сохранять логику проверки с типом данных, прикрепляя методы к записи:

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())

Семантика копирования для записей почти так же удобна, как и установка свойства. Проверка не происходит с набором свойств, но легко отфильтровать список записей только по допустимым.

2 голосов
/ 19 января 2010

На самом деле это должен быть хороший способ справиться с этим. Наличие вашей логики проверки в конструкторе поможет вам в дальнейшем подумать о коде, поскольку объект неизменен. Это также открывает возможности многопоточности.

Неизменяемая версия

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)    

Изменяемая версия

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 голосов
/ 19 января 2010

Вы смотрели на мой проект FunctionalNHibernate?Он разработан как слой поверх nhibernate, чтобы позволить вам декларативно отображать записи в базе данных.Это первые дни, но это почти годно к употреблению: http://bitbucket.org/robertpi/functionalnhibernate/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...