Entity Framework in Azure Function in Visual Studio - c#

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;)

Related

Change DB name for Entity Framework DbContext

I have inherited an application which is using Entity Framework to access a SQL Server database. The DbContext class has the constructor as shown below, where BuildingPermits is the name of the initial catalog.
I would like to be able to switch between databases (with the same connection) via a config file instead of changing the code.
How can I accomplish this?
public BuildingPermitsDbContext() : base("BuildingPermits")
{
Database.SetInitializer<BuildingPermitsDbContext>(null);
}
You can try this.
using System.Configuration;
public BuildingPermitsDbContext() : base(DatabaseName())
{
Database.SetInitializer<BuildingPermitsDbContext>(null);
}
private static string DatabaseName()
{
var db = ConfigurationManager.AppSettingss["desiredDbName"];
return db;
}

How to create the first version of database file from code EF Core

I am new to EF Core 3.1.22 using it with my .NET 4.6 desktop application. I am able to create the database and migrations using the package manager console, but my code doesn't generate the database file on its own at first run, when the database doesn't exist yet.
If I create the database using Update-Database from the package manager console, the file is created.
How can I update this code to generate the database file from code at first run and then apply database.migrate on that?
public class MyDbContextFactory : IDesignTimeDbContextFactory<MyDbContext>, IMyDbContextFactory
{
public MyDbContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<MyDbContext>();
optionsBuilder.UseSqlite($#"Data Source={DbConfiguration.GetDatabasePath()};", options =>
{
options.MigrationsAssembly(Assembly.GetExecutingAssembly().FullName);
});
return new MyDbContext(optionsBuilder.Options);
}
public MyDbContext CreateDbContext()
{
var dbcontext= CreateDbContext(new[] { "" });
dbcontext.Database.Migrate();
return dbcontext;
}
}
Your connection string doesn't allow the database to be created, see the SQLite provider docs.
Either change it to Mode=ReadWriteCreate or remove it entirely as it's the default setting.

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());
}
}

SQLite scaffolding with Entity Framework Core

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

System.data.SQLite entity framework code first programmatic providername specification

I've spent a while on this now and have only found a workaround solution that I'd rather not do...
I have a context as shown below. Is there a programmatic way to specify the database to connect to via the constructor, and get it to use the System.Data.SQLite entity framework provider to connect to a SQLite database? This is working via the app.config (with a connectionstring called "Context"), but not via any programmatic way I can find of supplying it. I have tried using an entity connectionstring builder and that produces the following string:
provider=System.Data.SQLite;provider connection string='data
source="datafile.db"'
When the context is first queried with this string I get a message "Keyword not supported: 'provider'."
public class Context : DbContext
{
public IDbSet<Test> Tests { get; set; }
public Context()
: base("Context")
{
}
}
*Edit.
I may have solved this by implementing my own connectionfactory:
public class ConnectionFactory : IDbConnectionFactory
{
public DbConnection CreateConnection(string nameOrConnectionString)
{
return new SQLiteConnection(nameOrConnectionString);
}
}
Then setting:
Database.DefaultConnectionFactory = new ConnectionFactory();
However, it seems like there should be a built in way to do this, and also one that does not involve overriding the global default connection factory.

Categories