Как использовать базу данных Entity Framework в памяти в F #? - PullRequest
1 голос
/ 15 апреля 2019

Я пытаюсь использовать Entity Framework Core с F # с базой данных в памяти для очень простого варианта использования:

open System
open Microsoft.EntityFrameworkCore

type Position = {
    X: double
    Y: double
}

type Airport = {
    Id: Guid
    Name: string
    Position: Position
}

type MyContext =
    inherit DbContext

    new() = { inherit DbContext() }
    new(options: DbContextOptions<MyContext>) = { inherit DbContext(options) }

    override __.OnConfiguring optionsBuilder =
        if optionsBuilder.IsConfigured <> false then
            optionsBuilder.UseInMemoryDatabase("database_name") |> ignore

    [<DefaultValue>]
    val mutable airports: DbSet<Airport>
    member x.Airports
        with get() = x.airports
        and set value = x.airports <- value

module AirportRepository =
    let getAirport id =
        use context = new MyContext()
        query {
            for airport in context.Airports do
                where (airport.Id = id)
                select airport
                exactlyOne
        } |> (fun x -> if box x = null then None else Some x)

    let addAirport (entity: Airport) =
        use context = new MyContext()
        context.Airports.Add(entity) |> ignore
        context.SaveChanges true |> ignore

[<EntryPoint>]
let main argv =
    let airport = {
        Id = Guid.NewGuid()
        Name = "Michelle"
        Position = {
            X = 42.0
            Y = 42.0
        }
    }
    AirportRepository.addAirport airport
    0

, но он не работает и выдает следующее исключение:

Unhandled Exception: System.InvalidOperationException: No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application se
rvice provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.Initialize(IServiceProvider scopedProvider, IDbContextOptions contextOptions, DbContext context)
   at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
   at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.EntryWithoutDetectChanges[TEntity](TEntity entity)
   at Microsoft.EntityFrameworkCore.DbContext.SetEntityState[TEntity](TEntity entity, EntityState entityState)
   at Program.AirportRepository.addAirport(Airport entity) in C:\Users\eperret\RiderProjects\FSharpCore\FSharpCore\Program.fs:line 43
   at Program.main(String[] argv) in C:\Users\eperret\RiderProjects\FSharpCore\FSharpCore\Program.fs:line 56

Как я могу заставить его работать, присутствует переопределение OnConfiguring, поэтому я не совсем то, что мне здесь не хватает.

Ответы [ 2 ]

3 голосов
/ 15 апреля 2019

Возможно, мне интересно, виновна ли эта строка:

if optionsBuilder.IsConfigured <> false then
            optionsBuilder.UseInMemoryDatabase("database_name") |> ignore

EFCore должен вызывать OnConfiguring только один раз за DbContext экземпляр, поэтому вам может не понадобитьсяпроверьте IsConfigured здесь.Попробуйте удалить эту ветку if и попробуйте снова?

0 голосов
/ 15 апреля 2019

Было несколько проблем:

  • Как указал Мэтью Эбботт, метод OnConfiguring не был должным образом реализован и должен был проверить, не был ли он уже настроен (а не наоборот, как я делал изначально)
  • Похоже, мне нужно было иметь только простые типы в моем определении сущности, а не сложные типы (потому что это будет рассматриваться как другая сущность

Решение:

open System
open Microsoft.EntityFrameworkCore


[<CLIMutable>]
type Airport = {
    Id: Guid
    Name: string
    X: double
    Y: double
}

type MyContext =
    inherit DbContext

    new() = { inherit DbContext() }
    new(options: DbContextOptions<MyContext>) = { inherit DbContext(options) }

    override __.OnConfiguring optionsBuilder =
        if optionsBuilder.IsConfigured <> true then
            optionsBuilder.UseInMemoryDatabase("database_name") |> ignore

    [<DefaultValue>]
    val mutable airports: DbSet<Airport>
    member x.Airports
        with get() = x.airports
        and set value = x.airports <- value

module AirportRepository =
    let getAirport id =
        use context = new MyContext()
        query {
            for airport in context.Airports do
                where (airport.Id = id)
                select airport
                exactlyOne
        } |> (fun x -> if box x = null then None else Some x)

    let addAirport (entity: Airport) =
        use context = new MyContext()
        context.Airports.Add(entity) |> ignore
        context.SaveChanges true |> ignore

[<EntryPoint>]
let main argv =
    let myGuid = Guid.NewGuid()
    let airport = {
        Id = myGuid
        Name = "Michelle"
        X = 42.0
        Y = 42.0
    }
    AirportRepository.addAirport airport
    let thisAirport = AirportRepository.getAirport myGuid
    assert (thisAirport = Some airport)
    0
...