SQLite scaffolding with Entity Framework Core - c#

When I run
Scaffold-DbContext "Filename=mydatabase.sqlite3" Microsoft.EntityFrameworkCore.Sqlite
I get an empty context
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
namespace MyNamespace
{
public partial class mydatabaseContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite(#"Filename=mydatabse.sqlite3");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
}
Am I doing something wrong. Is this available for SQLite?
I have a single table in the database with id and name, just a simple example to get me going.

It is creating a new database in bin folder because of the relative path in the connection string. I used new connection string.
Scaffold-DbContext "DataSource=C:\dev\mydatabase.sqlite3" Microsoft.EntityFrameworkCore.Sqlite

Paths are resolved relative to the output directory. (a.k.a. bin.) Ensure your database file is copied to the output directory on build.
Do this in csproj by setting Copy to Output Directory to Copy if newer.
Do this on xproj by adding the following to your project.json.
{
"publishOptions": {
"include": [
"mydatabase.sqlite"
]
}
}

you can try:
Scaffold-DbContext "DataSource=PATH\mydatabase.sqlite3 "Microsoft.EntityFrameworkCore.Sqlite -OutputDir Models

Related

Register EF Core in Prism in full .NET Framework

I want to use EF.Core 2.2.6 in a .Net Framework (4.6.2) project. I have created a separate project for the database.
I want to register the DbContext in the main project using dependency injection over the Prism framework (Unity).
var optionsBuilder = new DbContextOptionsBuilder<DbContext>();
optionsBuilder.UseSqlite(#"Data Source=CustomerDB.db");
containerRegistry.GetContainer().RegisterType<DbContext, CrossSettingContext>();
containerRegistry.GetContainer().RegisterType<DbContext>(new InjectionConstructor(optionsBuilder));
The database context:
public class CrossSettingContext : DbContext
{
private static Action<DbContextOptionsBuilder> onConfigure;
#pragma warning restore 649
public CrossSettingContext(DbContextOptions<CrossSettingContext> options) : base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.EnableSensitiveDataLogging(true);
onConfigure?.Invoke(optionsBuilder);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Setting>().Map();
}
}
I get the following exception. The question is if I am using the right approach for registering EF Core.
System.InvalidOperationException: "No member matching data has been found.
Error in: RegisterType(Invoke.Constructor(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder`1[Microsoft.EntityFrameworkCore.DbContext]))
I found this question -> but I need EF Core 2.2.6 and not Entity Framework 6.0
The answer from Haukinger is partially correct, but missing quite a bit of important information.
What you will want to do something like:
var optionsBuilder = new DbContextOptionsBuilder<CrossSettingContext>();
optionsBuilder.UseSqlite( #"Data Source=CustomerDB.db" );
However you do not need anything Container Specific AT ALL here. All you really need is:
containerRegistry.RegisterInstance(optionsBuilder.Options);
You do not actually need to register the CrossSettingContext if you want a new instance each time it's resolved. Though you could do the following if you want a singleton:
containerRegistry.RegisterSingleton<CrossSettingContext>();
When you want to use it you can just inject the context in your ViewModel/Services like:
public class ViewAViewModel
{
public ViewAViewModel(CrossSettingContext context)
{
// Do Stuff
}
}

Deployed Azure Function gives a ProviderName error

I have an Azure function application that when I debug it in my local PC, it won't give any error and will work correctly, but when I deploy it into the Azure Functions web, it will throw an error indicating that my Entities connection doesn't have the ProviderName specified.
I followed the solutions given by Missing ProviderName when debugging AzureFunction as well as deploying azure function, I have created a myDBContextConfig and added it to the Auto Generated dbContext file from my .edmx, but I still continue to have the same problem after deploying.
Here are some screenshots and config data I'm using:
the Error:
The local.settings.json:
{ "IsEncrypted": false,
"Values": {
//Some Values
},
"ConnectionStrings": {
"Entities": {
"ConnectionString": "metadata=res://*/Entities.csdl|res://*/Entities.ssdl|res://*/Entities.msl;provider=System.Data.SqlClient;provider connection string='data source=ES-HHASQL01\\SQLES;initial catalog=Entities;persist security info=True;Integrated Security=False;User ID=****;Password=****;MultipleActiveResultSets=True;application name=EntityFramework'",
"ProviderName": "System.Data.EntityClient"
}
}
}
And the Azure functions connection String:
The hidden connection follows the style of the quoted text below.
metadata=res:///Models.myDB.csdl|res:///Models.myDB.ssdl|res://*/Models.myDB.msl;provider=System.Data.SqlClient;provider connection string='data source=[yourdbURL];initial catalog=myDB;persist security info=True;user id=xxxx;password=xxx;MultipleActiveResultSets=True;App=EntityFramework
If any one can help me with this I would really appreciate it. Thank you.
Edit:
Well I have tested the issue with the code provided by #Joey Cai, and made the next changes:
the new App Settings connection string is has follows:
Data Source=tcp:*.database.windows.net,1433;Initial Catalog=***MultipleActiveResultSets=true;User ID=*;Password=***;Connection Timeout=30;App=EntityFramework;
I added the database configuration class to the Auto generated code from the dbContext has follows:
[DbConfigurationType(typeof(EntitiesConfig))]
public partial class Entities : DbContext
{
public Entities()
: base("name=Entities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
}
and created the class has especified by: #Joey Cai
namespace SameHasDbContext
{
public class EntitiesConfig : DbConfiguration
{
public EntitiesConfig()
{
SetProviderServices("System.Data.EntityClient", SqlProviderServices.Instance);
SetDefaultConnectionFactory(new SqlConnectionFactory());
}
}
}
But know I'm getting this error when running the azure function only if the connection type is SQLServer or SQLAzure, if it's set to Custom it still shows the ProviderNamer error shown before:
You can't add EF metadata about the connection in Azure Functions, as they do not use an app.config in which to specify it. This is not a part of the connection string, but is metadata about the connection besides the connection string that EF uses to map to a specific C# Class and SQL Provider etc. To avoid this, you could following the code as below.
[DbConfigurationType(typeof(DBContextConfig))]
partial class
{
public Entities(string connectionString)
: base(connectionString)
{
}
}
public class DBContextConfig : DbConfiguration
{
public DBContextConfig()
{
SetProviderServices("System.Data.EntityClient", SqlProviderServices.Instance);
SetDefaultConnectionFactory(new SqlConnectionFactory());
}
}

How do I call SQLitePCL.Batteries.Init().?

I am attempting to create an SQLite database for my application and have come across this error.
System.Exception: 'You need to call SQLitePCL.raw.SetProvider(). If
you are using a bundle package, this is done by calling
SQLitePCL.Batteries.Init().'
I created a simple console app the run the exact same code for creation, with no issues. The code looks like this!
using (var dataContext = new SampleDBContext())
{
dataContext.Accounts.Add(new Account() { AccountName = name, AccountBalance = balance });
}
public class SampleDBContext : DbContext
{
private static bool _created = false;
public SampleDBContext()
{
if (!_created)
{
_created = true;
Database.EnsureDeleted();
Database.EnsureCreated();
}
}
protected override void OnConfiguring(DbContextOptionsBuilder optionbuilder)
{
optionbuilder.UseSqlite(#"Data Source="Source folder"\Database.db");
}
public DbSet<Account> Accounts { get; set; }
}
Can anyone shed any light on the issue? I installed the same Nuget Packages on both projects, the only difference between the two is the Data Source and the POCO classes I used for the database.
Thanks.
Edit
My program currently consists of a Console application that references a .Net Framework Class Library. The Console application simple has a constructor that looks like this:
public Program()
{
using (var db = new FinancialContext())
{
db.Accounts.Add(new Account() { AccountName = "RBS", AccountBalance=20 });
}
}
The Class Library has a FinancialContext as Follows:
public class FinancialContext : DbContext
{
public DbSet<Account> Accounts { get; set; }
public FinancialContext()
{
# Database.EnsureDeleted();
Database.EnsureCreated();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionbuilder)
{
optionbuilder.UseSqlite(#"Data Source="Some Source Folder"\Database.db");
}
}
The Above error is shown at the # symbol point, is there a problem with the way I am coding? I would really like to know what the issue is so I can fix it properly rather than apply a 'fix'. Also I tried the suggestion in the comments, but putting the code line SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_e_sqlite3()); in the Console Application gave the error SQLitePCL is not in the current context, which leaves me thinking I am missing a reference?
This happened to me when I tried to avoid any additional dependencies and went for the Microsoft.EntityFrameworkCore.Sqlite.Core package.
You should install and use the Microsoft.EntityFrameworkCore.Sqlite package instead, which has a dependency upon the SQLitePCLRaw package.
Install Nuget Package Microsoft.Data.Sqlite (not Microsoft.Data.Sqlite.Core). (my version is 2.2.2)
and use SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_e_sqlite3());
connection = new SqliteConnection("Data Source = Sample.db");
SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_e_sqlite3());
connection.Open();
but I advise use nuget package System.Data.SQLite instead Microsoft.Data.Sqlite
I had this very exact error. It turned out that I had package Microsoft.Data.Sqlite.Core (2.2.4) installed, but not SQLitePCLRaw.bundle_winsqlite3.
Installing package SQLitePCLRaw.bundle_winsqlite3 (1.1.13) solved the issue.
Switching from Microsoft.Data.Sqlite.Core to Microsoft.Data.Sqlite as Patrick said here did the trick for me
I got this issue when working with Microsoft.EntityFrameworkCore.Sqlite version 3.1.10. The above solutions did not work for me. Then I have modified the My DbContext as follows (added SQLitePCL.Batteries.Init(); to OnConfiguring method) and the issue is gone!!!
public class ApplicationDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Data Source=mydb.db");
SQLitePCL.Batteries.Init();
}
}
For some reason the Nuget Package hadn't installed the required references, reinstalled the package and it has corrected the issue!
Missing the SQLitePCL.raw* references.
I had the same issue when I try to use, Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6". What I did was downgrade the version into 2.2.2 which I was previously used. Then issue not occur.
On Xamarin.iOs I had the same problem.
Solution: Call SQLitePCL.Batteries_V2.Init() In the FinishedLaunching method of your AppDelegate class.
Source: https://learn.microsoft.com/en-us/dotnet/standard/data/sqlite/xamarin

Entity Framework in Azure Function in Visual Studio

In Visual Studio I have an Azure Function, written in C#, which is supposed to read from an Azure SQL database using Entity Framework (EF6).
I cannot get Entity Framework to work. When I publish the Azure Function I get the error:
The context is being used in Code First mode with code that was generated from an EDMX file for either Database First or Model First development. This will not work correctly. To fix this problem do not remove the line of code that throws this exception. If you wish to use Database First or Model First, then make sure that the Entity Framework connection string is included in the app.config or web.config of the start-up project. If you are creating your own DbConnection, then make sure that it is an EntityConnection and not some other type of DbConnection, and that you pass it to one of the base DbContext constructors that take a DbConnection. To learn more about Code First, Database First, and Model First see the Entity Framework documentation here: http://go.microsoft.com/fwlink/?LinkId=394715
None of this worked.
I also tried to add a project.json file in Azure as recommended by many websites but that didn’t change anything.
Here is the C#.
public static class Function1
{
[FunctionName("Function1")]
public static void Run([TimerTrigger("*/100 * * * * *")]TimerInfo myTimer, TraceWriter log)
{
try {
using (var qc = new quotecandyEntities()) {
if (qc.Users.Any()) {
log.Info($"The last user is {qc.Users.Last().Email}.");
} else {
log.Info("No users found in database.");
}
}
} catch (Exception ex) {
log.Error($"Error: {ex.Message}");
}
}
}
According to your description, I assumed that you are using Database First or Model First, and you configured the wrong Entity Framework connection string for your Entity Data Model. I tested and found that if my directly copy the connection string from Azure Portal while I am using Database First, I would encounter the similar issue you provided as follows:
For Database First, I would recommend you modify the generated Model.Content.cs and configure your DbContext as follows:
public partial class Entities : DbContext
{
public Entities():base(ConfigurationManager.ConnectionStrings["Entities"].ConnectionString)
{
}
}
Note: You could modify the t4 template and make sure you modification for your DbContext does not overridden after you updated the model from your database.
For dev, you could set your connection string under local.settings.json file as follows:
"ConnectionStrings": {
"Entities": "metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string='data source={server-name}.database.windows.net;initial catalog={db-name};persist security info=True;user id={username};password={password};MultipleActiveResultSets=True;App=EntityFramework'"
}
Before publishing to azure, you could create a connection string with the same as you configured under local.settings.json file and set the connection string as follows:
Moreover, you could follow this similar issue about the approach for using EF Database First in Azure Function.
since i had hard time setting this even with post here is the complete version
project1 (azure function) :
local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"AzureWebJobsDashboard": "UseDevelopmentStorage=true",
"schedule": "*/1 * * * * *"
},
"ConnectionStrings": {
"dbEntities": "metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string='data source=someAzureServer.database.windows.net;initial catalog=someDB;persist security info=True;user id=foo;password=XXXX;MultipleActiveResultSets=True;App=EntityFramework'",
"ProviderName": "System.Data.EntityClient"
}
}
Project2(dll):
Model1.Context.cs
namespace main2
{
using System;
using System.Configuration;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
public partial class dbEntities : DbContext
{
public crypto_dbEntities()
: base(ConfigurationManager.ConnectionStrings["dbEntities"].ConnectionString)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
}
now rename :
-connectionstring name
-server name
-db name
-user name
-password
so i remember later too;)

Schema independent Entity Framework Code First Migrations

I have troubles using Entity Framework migrations targeting Oracle databases since schema name is included in migrations code and for Oracle, schema name is also user name. My goal is to have schema-independent Code First Migrations (to be able to have one set of migrations for testing and production enviroments).
I have already tried this approach (using Entity Framework 6.1.3):
1) I have schema name in Web.config:
<add key="SchemaName" value="IPR_TEST" />
2) My DbContext takes schema name as a constructor parameter:
public EdistributionDbContext(string schemaName)
: base("EdistributionConnection")
{
_schemaName = schemaName;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema(_schemaName);
}
3) I had to implement IDbContextFactory for Entity Framework Migrations to be able to create my DbContext which does not have parameterless constructor:
public class MigrationsContextFactory : IDbContextFactory<EdistributionDbContext>
{
public EdistributionDbContext Create()
{
return new EdistributionDbContext(GetSchemaName());
}
}
4) I also configured Migration History Table to be placed within correct schema:
public class EdistributionDbConfiguration : DbConfiguration
{
public EdistributionDbConfiguration()
{
SetDefaultHistoryContext((connection, defaultSchema)
=> new HistoryContext(connection, GetSchemaName()));
}
}
5) I modified code generated for migrations to replace hardcoded schema name. Eg. I replaced CreateTable("IPR_TEST.Users") with CreateTable($"{_schema}.Users"). (_schema field is set according to the value in Web.config).
6) I use MigrateDatabaseToLatestVersion<EdistributionDbContext, MigrationsConfiguration>() database initializer.
Having all this set up, I still have problems when I switch to different schema (eg. via web.config transformation) - an exception is thrown telling me that database does not match my model and AutomaticMigrations are disabled (which is desired). When I try to execute add-migration a new migration is generated where all object should be moved to different schema (eg: MoveTable(name: "IPR_TEST.DistSetGroups", newSchema: "IPR");, which is definitely not desired.
For me it seems that schema name is hard-wired somewhere in model string-hash in migration class (eg. 201509080802305_InitialCreate.resx), ie:
<data name="Target" xml:space="preserve">
<value>H4sIAAAAAAAEAO09227jO... </value>
</data>
It there a way how to tell Code First Migrations to ignore schema name?
You can create a derived DbContext and "override" modelBuilder.HasDefaultSchema(...) in OnModelCreating:
public class TestDbContext : ProductionDbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema("TestSchema");
}
}
Then you can create migrations for both contexts. See this question on how to create two migrations in one project.
The downside of this approach is that you have to maintain two seperate migrations. But it gives you the opportunity to adjust the configuration of your TestDbContext.
I was faced to same problem and thanks to your aproach I finally found a solution that seems to work pretty well:
1) I have the schema name in Web.config app settings:
<add key="Schema" value="TEST" />
2) I have a history context:
public class HistoryDbContext : HistoryContext
{
internal static readonly string SCHEMA;
static HistoryDbContext()
{
SCHEMA = ConfigurationManager.AppSettings["Schema"];
}
public HistoryDbContext(DbConnection dbConnection, string defaultSchema)
: base(dbConnection, defaultSchema)
{ }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema(SCHEMA);
}
}
3) I have a db configuration that reference my history db context:
public class MyDbConfiguration : DbConfiguration
{
public MyDbConfiguration()
{
SetDefaultHistoryContext((connection, defaultSchema) => new HistoryDbContext(connection, defaultSchema));
}
}
4) And this is my db context:
public partial class MyDbContext : DbContext
{
public MyDbContext()
: base("name=MyOracleDbContext")
{ }
public static void Initialize()
{
DbConfiguration.SetConfiguration(new MyDbConfiguration());
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDbContext, Migrations.Configuration>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema(string.Empty);
}
}
5) Finally I call the Initialize method from the global.asax
protected void Application_Start()
{
MyDbContext.Initialize();
}
The key is to set the default schema of the db context to String.Empty and the schema of the history context to the correct one.
So when you create your migrations they are schema independant: the DefaultSchema variable of the resx of the migration will be blank. But the history db context schema is still correct to allow migrations checks to pass.
I am using the following nugets packages:
<package id="EntityFramework" version="6.2.0" targetFramework="net452" />
<package id="Oracle.ManagedDataAccess" version="12.2.1100" targetFramework="net452" />
<package id="Oracle.ManagedDataAccess.EntityFramework" version="12.2.1100" targetFramework="net452" />
You can then use Oracle migrations with success on different databases.

Categories