dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.64k stars 3.15k forks source link

"You need to call SQLitePCL.raw.SetProvider()" error when using Microsoft.EntityFrameworkCore.Sqlite 5.0.4 via C++\CLI wrapper #24493

Open bairog opened 3 years ago

bairog commented 3 years ago

I have a solution with the following structure:

DAL.Test runs without any problems, but DAL.Interop.Test throws an exception (inside DAL class library):

You need to call SQLitePCL.raw.SetProvider(). If you are using a bundle package, this is done by calling SQLitePCL.Batteries.Init().

NB! If I switch from Microsoft.EntityFrameworkCore.Sqlite provider to Devart.Data.SQlite.EFCore provider - both test applications (.NET and C++) run without any problems.

NB2! If I remember correctly code was working with no problems with Microsoft.EntityFrameworkCore.Sqlite 3.1 on .NET Core 3.1.

Sample repo - https://github.com/bairog/EFCore5SQLiteCLRTest Compile it (for some reason you need to compile twice for compiling DAL.Interop.Test project) and start debugging DAL project (it starts DAL.Interop.Test.exe in project Debug settings)

Stack traces

Source: SQLitePCLRaw.core
You need to call SQLitePCL.raw.SetProvider(). If you are using a bundle package, this is done by calling SQLitePCL.Batteries.Init().
   at SQLitePCL.raw.get_Provider()
   at SQLitePCL.raw.sqlite3_open_v2(utf8z filename, sqlite3& db, Int32 flags, utf8z vfs)
   at Microsoft.Data.Sqlite.SqliteConnection.Open()
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnection(Boolean errorsExpected)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternal(Boolean errorsExpected)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.Open(Boolean errorsExpected)
   at Microsoft.EntityFrameworkCore.Sqlite.Storage.Internal.SqliteDatabaseCreator.Exists()
   at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.Exists()
   at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.GetAppliedMigrations()
   at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.GetAppliedMigrations(DatabaseFacade databaseFacade)
   at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.GetPendingMigrations(DatabaseFacade databaseFacade)
   at DAL.CRUD.CreateDbContext() in D:\EFCore5SQLiteCLRTest\DAL\CRUD.cs:line 14

Provider and version information

EF Core version: 5.0.4 Database provider: Microsoft.EntityFrameworkCore.Sqlite Target framework: .NET 5.0 Operating system: Windows 10 x64 1909 IDE: Visual Studio 2019 16.9.2 REL Community

ajcvickers commented 3 years ago

/cc @bricelam

bricelam commented 3 years ago

Is SQLitePCLRaw.batteries_v2.dll getting trimmed/not getting copied to the output directory?

bairog commented 3 years ago

@bricelam SQLitePCLRaw.batteries_v2.dll is present in output directory. Don't know if it is trimmed - it is 6Kb.

bairog commented 3 years ago

.NET 6-preview5 was out almost a month ago. Any updates on this issue?

lauxjpn commented 3 years ago

Came across the same exception while checking the scope of an EF Core bug (unrelated to this issue here) on other providers.

Solved it for me by adding the SQLitePCLRaw.bundle_e_sqlite3 package reference to the project (I was not using the Microsoft.EntityFrameworkCore.Sqlite NuGet package, but a locally compiled build instead):

<ItemGroup>
    <PackageReference Include="SQLitePCLRaw.core" Version="2.0.4" />
    <PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.0.4" />
</ItemGroup>
bricelam commented 3 years ago

In that case, this is probably a dupe of https://github.com/ericsink/SQLitePCL.raw/issues/252

bairog commented 2 years ago

@bricelam Is there an update on this issue? Is this planned to be a patch version of Microsoft.EntityFrameworkCore.Sqlite 5.0.x or exclusive to Microsoft.EntityFrameworkCore.Sqlite 6?

bricelam commented 2 years ago

We'd love to get some community help on this issue. Our team has little-to-no experience with C++/CLI. If you or anyone else wants to dig into this, write a detailed explanation of the problem, and propose a fix. We'd be happy do discuss it as a team and possibly move forward with a community PR.

bricelam commented 2 years ago

Essentially this code isn't working for some reason on C++/CLI:

https://github.com/dotnet/efcore/blob/786cb40576d47874549753e6d92fbcf3e65a4f64/src/Microsoft.Data.Sqlite.Core/SqliteConnection.cs#L51-L53

Either because SQLitePCLRaw.batteries_v2.dll isn't getting copied to the output directory, or because the type or method is being trimmed, or for some other unknown reason.

bairog commented 2 years ago

Either because SQLitePCLRaw.batteries_v2.dll isn't getting copied to the output directory, or because the type or method is being trimmed.

As I wrote above SQLitePCLRaw.batteries_v2.dll is present in output directory. Don't know if it is trimmed - it is 6Kb.

jjxtra commented 2 years ago

Same issue in .net 6 in vs 2022 debugger, x64 Windows 11 machine, any cpu debug build. Just a single asp.net core project using sqlite entity framework.

bairog commented 2 years ago

@bricelam Any updates? More than a year has passed from bug report date. EF Core 6 has been release and there are some previews of EF Core 7. Did you obtained some help from Microsoft C++\CLI team?

bricelam commented 2 years ago

Does manually adding a call to SQLitePCL.Batteries_V2.Init() in you app work around the issue?

bairog commented 2 years ago

Calling SQLitePCL.Batteries_V2.Init() changes nothing in my case..

SoftCircuits commented 2 years ago

Is there nothing Microsoft can tell us about this?

I'm using .NET 6. And I'm trying to follow Microsoft documentation.

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.7">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="6.0.7" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.7">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
  </ItemGroup>

add-migration ran without errors.

update-database failed.

PM> update-database
Build started...
Build succeeded.
System.Exception: You need to call SQLitePCL.raw.SetProvider().  If you are using a bundle package, this is done by calling SQLitePCL.Batteries.Init().
   at SQLitePCL.raw.get_Provider()
   at SQLitePCL.raw.sqlite3_open_v2(utf8z filename, sqlite3& db, Int32 flags, utf8z vfs)
   at SQLitePCL.raw.sqlite3_open_v2(String filename, sqlite3& db, Int32 flags, String vfs)
   at Microsoft.Data.Sqlite.SqliteConnectionInternal..ctor(SqliteConnectionStringBuilder connectionOptions, SqliteConnectionPool pool)
   at Microsoft.Data.Sqlite.SqliteConnectionFactory.GetConnection(SqliteConnection outerConnection)
   at Microsoft.Data.Sqlite.SqliteConnection.Open()
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnection(Boolean errorsExpected)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternal(Boolean errorsExpected)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.Open(Boolean errorsExpected)
   at Microsoft.EntityFrameworkCore.Sqlite.Storage.Internal.SqliteDatabaseCreator.Exists()
   at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.Exists()
   at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(String targetMigration, String connectionString, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabaseImpl(String targetMigration, String connectionString, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)

Not sure what that was about C++. This is a C# project.

bricelam commented 2 years ago

@SoftCircuits I think you meant to use the Microsoft.EntityFrameworkCore.Sqlite package instead. The Core one is for those who want to provide their own native SQLite library.

- <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="6.0.7" />
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.7" />
SoftCircuits commented 2 years ago

@bricelam Sorry, that was the issue. Naming is a little confusing here. I appreciate you taking a look.

pajeb4you commented 2 years ago

For my .NET Standard 2.1 project, I was getting same error. Once I added Microsoft.Data.Sqlite package, all started working fine.

PaddiM8 commented 1 year ago

I'm getting this error with native AOT on .NET 7. I'm using Microsoft.Data.Sqlite.

bairog commented 1 year ago

@bricelam Same error with latest Microsoft.EntityFrameworkCore.Sqlite 7.0.3 on .NET 7.0 (latest Visual Studio 2022 17.5.6 Preview)

Does manually adding a call to SQLitePCL.Batteries_V2.Init() in you app work around the issue?

If I add this line before DbContext access - I get an error (despite of SQLitePCLRaw.batteries_v2.dll is present in output directory);

System.IO.FileNotFoundException: 'Could not load file or assembly 'SQLitePCLRaw.batteries_v2, Version=2.1.4.1835, Culture=neutral, PublicKeyToken=8226ea5df37bcae9'. Не удается найти указанный файл.'

Did you obtained some help from Microsoft C++\CLI team? This issue exists for almost 2 years :(

woutervanranst commented 1 year ago

I had erroneously added this package, which does not include the BCL <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="7.0.4" />

Adding this version instead fixed it for me <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.4" />

rgwood commented 9 months ago

^ Similar to this, replacing Microsoft.Data.Sqlite.Core with Microsoft.Data.Sqlite fixed the issue for me.

I wasn't intentionally using the Core package, but it's one of the first search results for "sqlite" in Visual Studio's NuGet UI and I didn't notice the .Core suffix when adding it to my project.

wz172 commented 7 months ago

I encountered the same error, the solution is, package.PackageReference Include = "Microsoft EntityFrameworkCore. Sqlite. Core" Version = "6.0.26" / & gt;Change to <PackageReference Include = "Microsoft. EntityFrameworkCore. Sqlite" Version = "6.0.26" / & gt;

gulachek commented 4 weeks ago

I encountered this in an ASP.NET / ASP.NET Core web app attempting to use Microsoft.Data.Sqlite on Windows 11. It's not the EntityFrameworkCore flavor, but I'm guessing my analysis will be relevant and unlikely to be a separate issue.

What seems to be going wrong is that ASP.NET "shadow copies" managed assemblies (so C# dlls) to a temp folder. This is where the SQLitePCL assemblies are loaded from. The Batteries_V2.Init() function then tries to load e_sqlite3.dll by looking up the native (C/C++) DLL relative to the folder that the SQLitePCL assembly was loaded from. Because ASP.NET copies the managed assembly to the temp folder but not the native DLL, the candidate absolute paths that SQLitePCL attempts to load with LoadLibrary are invalid.

These technologies are newer to me so I'm not yet to a point where I can suggest an upstream fix for a PR. I'm happy to provide more investigation details for someone when I'm closer to my dev machine.

My current status is that I'm trying to find a workaround to get the native DLL to be found by Batteries.Init(). Otherwise I'm going to assess if this bug is enough of a roadblock to try alternative strategies to accomplish my project's goal. If I find a decent workaround, I'll try to remember to update this issue with my findings.