如何在F#中使用Entity Framework内存数据库?

问题描述 投票:1回答:2

我试图将带有F#的Entity Framework Core与内存数据库一起用于一个非常简单的用例:

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覆盖存在,所以我不是我在这里缺少的。

.net-core f# entity-framework-core in-memory-database
2个回答
3
投票

猜测,我想知道这条线是否是罪魁祸首:

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

每个OnConfiguring实例只能由EFCore调用DbContext,所以你可能不需要在这里检查IsConfigured。尝试删除if分支,然后再试一次?


0
投票

有一些问题:

  • 正如Matthew Abbott指出的那样,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
© www.soinside.com 2019 - 2024. All rights reserved.