Преобразование объектов данных - F#, Fabulous, sql-net-pcl и клиентская библиотека веб-API

Я новичок в F# и пытаюсь найти лучший способ преобразования между похожими, но разными объектами данных, минимизируя дублирование кода. Я пишу приложение, используя платформу Fabulous F# MVU для Xamarin Forms.

Я использую sqlite-net-pcl для сохранения данных, который вызывает объект при создании таблицы базы данных и взаимодействии с этой таблицей, и я создал AuthorObject:

          type AuthorObject() =
        [<PrimaryKey>] // sqlite-net-pcl attribute
        member val AuthorId = 0 with get, set
        member val Username = "" with get, set
        member val Token = "" with get, set

Fabulous использует типы записей для моделей, и я создал тип записи, который будет передаваться внутри Fabulous:

          type Author = 
        { AuthorId: int
          Username: string
          Token: string }

Но мне также нужно взаимодействовать с библиотекой API веб-службы (написанной на C#), которая возвращает объект. имеет свойства с такими же именами, как указано выше, а также многое другое, о чем мне не нужно беспокоиться. Я не могу изменить определение.

Таким образом, похоже, что в настоящее время ограничения заключаются в том, что sqlite-net-pcl нужен объект с членами, Fabulous нужен тип записи, и у меня есть этот объект, поступающий из клиентской библиотеки API службы, который я не могу изменить. Мне нужно преобразовать между этими типами, и я изначально надеялся, что мне удастся просто:

          let convertToObject author = // Was hoping author param here could be generic in some way
        let obj = AuthorObject()
        obj.AuthorId <- author.AuthorId
        obj.Username <- author.Username
        obj.Token <- author.Token
        obj

    let convertToModel (obj: AuthorObject) : Author =
        { AuthorId = obj.AuthorId
          Username = obj.Username
          Token = obj.Token }

Но с дополнительным усложнением, я обнаружил, что теперь мне нужно сделать что-то вроде этого, чтобы компилятор был доволен:

          let convertAuthorDetailDtoToObject (dto: AuthorDetailDto) =
        let obj = AuthorObject()
        obj.AuthorId <- dto.AuthorId
        obj.Username <- dto.Username
        obj.Token <- dto.Token
        obj

    let convertAuthorToObject (author: Author) =
        let obj = AuthorObject()
        obj.AuthorId <- author.AuthorId
        obj.Username <- author.Username
        obj.Token <- author.Token
        obj

    let convertToModel (obj: AuthorObject) : Author =
        { AuthorId = obj.AuthorId
          Username = obj.Username
          Token = obj.Token }

Вот несколько исходных файлов:

DomainModels.fs:

      namespace MyApp.Mobile

module DomainModels =
    type Author = 
        { AuthorId: int
          Username: string
          Token: string }

Автор.fs:

      namespace MyApp.Mobile.Repository

open SQLite
open Client // Provides AuthorDetailDto.
open MyApp.Mobile.DomainModels

module Author =
    type AuthorObject() =
        [<PrimaryKey>]
        member val AuthorId = 0 with get, set
        member val Username = "" with get, set
        member val Token = "" with get, set

    let convertToObject author =
        let obj = AuthorObject()
        obj.AuthorId <- author.AuthorId
        obj.Username <- author.Username
        obj.Token <- author.Token
        obj

    let convertToModel (obj: AuthorObject) : Author =
        { AuthorId = obj.AuthorId
          Username = obj.Username
          Token = obj.Token }

    let connect dbPath = async {
            let db = SQLiteAsyncConnection(SQLiteConnectionString dbPath)
            do! db.CreateTableAsync<AuthorObject>() |> Async.AwaitTask |> Async.Ignore
            return db
    }

    let purgeLoggedInAuthor dbPath = async {
        let! db = connect dbPath
        do! db.ExecuteAsync "DELETE FROM AuthorObject" |> Async.AwaitTask |> Async.Ignore
    }

    let insertLoggedInAuthor dbPath author = async {
        let! db = connect dbPath
        do! db.InsertAsync (convertToObject author) |> Async.AwaitTask |> Async.Ignore
    }

Первоначальный вызов выглядит так:

      insertLoggedInAuthor dbPath loggedInAuthor // loggedInAuthor is an AuthorDetailDto.

Ошибка FS0001 This expression was expected to have type 'DomainModels.Author' but here has type 'AuthorDetailDto' из-за того, что оба типа упоминаются в Author.fs.

Я пробовал возиться с inline и статические ограничения членов и попытка определить интерфейс, но из-за Author должны быть типом записи и не иметь возможности изменять AuthorDetailDto, этот подход не кажется жизнеспособным. Или, возможно, я просто недостаточно хорошо разбираюсь в F#.

Для тех, кто более знаком с F#, чем я, как лучше всего решить такую ​​ситуацию, чтобы минимизировать дублирование кода?

0 ответов

Другие вопросы по тегам