#.net-core #f# #entity-framework-core #in-memory-database
#.net-core #f# #entity-framework-core #база данных в памяти
Вопрос:
Я пытаюсь использовать 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:UserseperretRiderProjectsFSharpCoreFSharpCoreProgram.fs:line 43
at Program.main(String[] argv) in C:UserseperretRiderProjectsFSharpCoreFSharpCoreProgram.fs:line 56
Как я могу заставить это работать, переопределение OnConfiguring присутствует, поэтому я на самом деле не то, чего мне здесь не хватает.
Ответ №1:
Мне кажется, мне интересно, является ли эта строка виновником:
if optionsBuilder.IsConfigured <> false then
optionsBuilder.UseInMemoryDatabase("database_name") |> ignore
OnConfiguring
EFCore должен вызываться только один раз для каждого DbContext
экземпляра, поэтому проверка здесь может не понадобиться IsConfigured
. Попробуйте удалить эту if
ветку и повторить попытку?
Ответ №2:
Было несколько проблем:
- Как указал Мэтью Эбботт,
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