I am using NInject container for Dependency Injection and Entity Framework Core as ORM. The setup is as follows:
DB Context Class
public TarantoContext()
{
}
public TarantoContext(DbContextOptions<TarantoContext> options)
: base(options)
{
}
public virtual DbSet<FileData> FileData { get; set; }
public virtual DbSet<FileExport> FileExport { get; set; }
public virtual DbSet<FileStatus> FileStatus { get; set; }
public virtual DbSet<FileType> FileType { get; set; }
public static string ConnectionString { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(ConnectionString);
}
}
Program.cs
TarantoContext.ConnectionString = configurationManager.DatabaseConnection;
I am reading the configuration from json and passing it to the DataAccess layer (to the context class). I have a few tables in my database and taking database first approach I created the necessary data models and completed the dbcontext class code. I am able to fetch the data without any problems. Now I want to add-migration (I may have more changes to existing tables and may create new tables) and ran the following in package manager console:
Add-Migration InitialCreate
which resulted in the following error because the connectionstring property is null
I can fix this by hardcoding the connectionstring in the OnConfiguring method which I have tried without any problems:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
// The connection string needs to exist in the migration project for the purpose of migrations. Comment it in production.
optionsBuilder.UseSqlServer(
"Data Source=temp;Initial Catalog=Demo;Persist Security Info=True;User ID=temp;Password=temp;MultipleActiveResultSets=True;");
//optionsBuilder.UseSqlServer(ConnectionString);
}
}
but I do not think this is the correct way of doing migrations. Moreover I am not sure how to handle the migrations in productions if I am unable to set the connectionstring in Program.cs or outside of the dbcontext class. What I am interested in is learning any design pattern which other developers are using to handle this situation. Any advise is greatly appreciated.
In ASP.NET Core, you can load the connection string while setting up services in the ConfigureServices method. Use the following code:
services.AddDbContext<ApplicationDatabaseContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection"),
b => b.MigrationsAssembly("....")));
Now, the GetConnectionString call will retrieve the connection string from you configuration file i.e. appsettings.json. To handle different connection strings for different environments, you can override the default app settings using a appsettings.<Environment>.json file like appsettings.Production.json.
More on this here: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-2.2
Check out the relevant MSDN documentation pages for these things as they contain a lot of information.
Related
I'm using EntityFrameworkCore Code First to create my SQL migration scripts.
After every change in my model, I run Add-Migration changeInModel and a corresponding XXXXXXXX_changeInModel.cs file is being generated in my Migrations folder.
If I don't make any change in my models AND I run Add-Migration noChangeInModel , I was assuming (out of nowhere) no generation of XXXXXX_noChangeInModel.cs
However, EF Core is creating a XXXXXX_noChangeInModel.cs with an empty Up and Down methods.
Is that supposed to be the expected behavior? Or should EF Core just skip the generation of an empty .cs file? I can't find any reference to this in the documentation.
I have taken my main project and stripped out all the code up to the bare minimum to find out whether is the behavior or some sort of bug in my configuration.
Below the minimum core to reproduce generating empty Up/Down methods with no change in models, with the following Nuget packages:
Microsoft.EntityFrameworkCore 2.2.6
Microsoft.EntityFrameworkCore.SqlServer 2.2.6
Microsoft.EntityFrameworkCore.Tools 2.2.6
Microsoft.NETCore.App 2.2.0
namespace TestingEFCore
{
public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<BloggingContext>
{
public BloggingContext CreateDbContext(string[] args)
{
var connectionString = "Server=localhost;Database=TEST2;Integrated Security=SSPI;";
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlServer(connectionString);
return new BloggingContext(optionsBuilder.Options);
}
}
public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{ }
public DbSet<Blog> Blogs { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
}
I would expect no XXXXXX_noChangeInModel.cs being generated, but a I get migrations with empty Up/Down methods. I can't find the documentation to describe this use case.
I think it is expected behavior. Consider the case when you have no changes in model but you need to add some data in your db like this
public partial class your_migration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(#"your sql");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(#"sql to clean up data");
}
}
Without an empty migration for no changes in model generated it would be impossible to obtain such migration.
I created a web application and a model. Then I generated a dbcontext class and a database instance. After I built the project, I tried to connect to that database from Server Explorer in Visual Studio, but could not connect.
I tried to test connection but got an error:
This connection cannot be tested because the specified database does not exist or is not visible to the specified user
Whenever I tried to scaffold view or controller I got this error:
Unable to retrieve metadata for ... one or more validation errors were detected during model generation
ModelsTable is based on type TestModel that has no keys defined.
When I created database object in controller class and write query got same error no key defined.
Also made updates on packages and tried again. I think my connection string is correct.
Here is my model.
public class TestModel
{
[Key]
public string ID { get; } = Guid.NewGuid().ToString();
public string AreaName { get; set; }
public bool IsWorking { get; set; }
public string UserName { get; set; }
public DateTimeOffset Time { get; set; }
}
So I could not use scaffolding, Entity Framework and write query.
Here is my dbcontext class.
public class ModelDB : DbContext
{
public ModelDB()
: base("name=ModelDB")
{
}
public DbSet<TestModel> ModelsTable { get; set; }
}
I searched on internet tried founded solutions but did not understand and could not solve. I hope did not ask unnecessary questions. Thanks for your helping.
Are you using Code First? If so I think you need to generate migrations.
In visual studio go to Package Manager Console and run this commands:
Add-Migration "modelClassName"
Update-Database –Verbose
For more information refer to this link: https://msdn.microsoft.com/en-us/library/jj591621(v=vs.113).aspx
You are missing the set; in the field ID.
Here is my asp.net core project structure
1- ASP.NET CORE Web API (contains aspsettings.json)
"ConnectionStrings": {
"DefaultConnection": "Server=(local)\\SQLEXPRESS;Database=testdb;Trusted_Connection=True;"
}
2-SERVICES Project (Web API Call method from Services Project)
3-REPOSITORY Project (Services call method from Repository Project and Repository Project include the DATA Project where all the models are)
4-DATA Project where it's contain all the model with code first
public class TtEntities : DbContext
{
public virtual DbSet<RoomMessage> RoomMessage { get; set; }
public virtual DbSet<UserRoom> UserRoom { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(#"Server=(local)\SQLEXPRESS;Database=testdb;Trusted_Connection=True;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
....
As you can see, I hardcoded the connection on the method OnConfiguring which is not the best practice for sure.
Is there a way to pass the connection string from the configuration file of the Web API Project?
Is update database command will still work if we pass the connection from the file aspsettings.json from web api project ?
Thanks a lot
A simple solution is like this:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}
}
Consider how DefaultConnection is used in line 13. Also a sample appsettings is like as follow:
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-WebApplication5;"
}
}
DI solves this problem perfectly and .NET Core 2.0 has Microsoft DI thats provides clearly experience with DI.
oh, lets starts(i think that DATA Project and REPOSITORY Project should be one)
from REPOSITORY Project
change your REPOSITORYClass to
public class REPOSITORYClass
{
private readonly TtEntities _db;
public REPOSITORYClass (TtEntities db){
_db = db;
}
//some your staff of REPOSITORYClass thats uses _db
}
now go to SERVICES Project
lets change some service that uses REPOSITORYClass
public class SomeService
{
private readonly REPOSITORYClass _repo;
public SomeService (REPOSITORYClass repo){
_repo = repo;
}
//other staff of SomeService thats uses _repo
}
after that go to ASP.NET CORE Web API startup file and add to
public void ConfigureServices
// Get connection of your repo
string connection = Configuration.GetConnectionString("DefaultConnection");
// add TtEntities as service
services.AddDbContext<TtEntities>(options =>
options.UseSqlServer(connection));
//add your repo
services.AddTransient<REPOSITORYClass>();
//add your service
services.AddTransient<SomeService>();
now go to the contoller thats uses your SomeService
public class SomeController: Controller
{
private readonly SomeService _someService;
public SomeController(SomeService someService){
_someService = someService;
}
//And use whatever your wants from your service that injected with deps of repo and injected db entity with connection
public string SomeMethod()
{
return _someService.SomeMethod();
}
}
And use whatever your wants from your service that injected with deps of repo and injected db entity with connection
thats all
PS also recommend to read this Introduction to Dependency Injection in ASP.NET Core
Using Microsoft.EntityFrameworkCore.SQLite, I'm attempting to create a code level creation of a database, and add a simple row to a table. I get the error, SQLite error: no such table Jumplists.
From last to first, here are the classes
using JumpList_To_Clipboard.Data.Tables;
using Microsoft.EntityFrameworkCore;
namespace JumpList_To_Clipboard.Data
{
public class DataSQLite : IData
{
public const string DATABASE = "data.sqlite";
public DataSQLite()
{
using (var db = new SQLiteDbContext(DATABASE))
{
// Ensure database is created with all changes to tables applied
db.Database.Migrate();
db.JumpLists.Add(new JumpList { Name = "Default" });
db.SaveChanges(); // Exception thrown here
}
}
}
}
The DbContext class
using JumpList_To_Clipboard.Data.Tables;
using Microsoft.EntityFrameworkCore;
namespace JumpList_To_Clipboard.Data
{
class SQLiteDbContext : DbContext
{
readonly string db_path;
public DbSet<JumpList> JumpLists { get; set; }
public DbSet<Group> Groups { get; set; }
public DbSet<Item> Items { get; set; }
public SQLiteDbContext(string database) : base()
{
db_path = database;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite(string.Format("Data Source={0}", db_path));
}
}
}
The JumpList class
using System.Collections.Generic;
namespace JumpList_To_Clipboard.Data.Tables
{
public class JumpList
{
public int JumpListId { get; set; }
public string Name { get; set; }
public List<Group> Groups { get; set; }
public List<Item> Items { get; set; }
}
}
The other two classes aren't worth repeating here, and don't give errors.
When I use the firefox sqlite extension to look at the data.sqlite file, none of my three tables are listed.
The command db.DataBase.Migrate says it
Applies any pending migrations for the context to the database.
What are pending migrations? I can't seem to find any documentation anywhere on these.
I'm combining examples from:
https://learn.microsoft.com/en-us/ef/core/get-started/netcore/new-db-sqlite
https://blogs.msdn.microsoft.com/dotnet/2016/09/29/implementing-seeding-custom-conventions-and-interceptors-in-ef-core-1-0/
Edit: If I replace db.Database.Migrate(); with db.Database.EnsureCreated(); it works. From the documentation, Migrate() is the same, but lets you create updates to the table structures, where EnsureCreated() does not. I'm confused.
So,
Microsoft has a serious issue making decent documentation, but I did find a site that has somewhat dated documentation for Learning Entity Framework Core, specifically migrations which is in the link.
At the top, it mentions,
If you have Visual Studio, you can use the Package Manager Console (PMC) to manage migrations.
Which led to the Package Manager Console page which states right at the top, that you need to have:
If you want to use the Package Manager Console to execute migrations command, you need to ensure that the latest version of Microsoft.EntityFrameworkCore.Tools is added to your project.json file.
The problem is, there is no project.json file anywhere in my project (or solution). After some searching, I found that via NuGet, to add Microsoft.EntityFrameworkCore.Tools
Then via Tools > NuGet Package Manager > Package Manager Console I was able to run the add-migration InitialDatabases command. The last part InitialDatabases is the name of the class it creates for you, and sticks in a folder called Migrations at the base of the project.
Now when:
context.Database.Migrate();
is run, all is well!
Try this (worked for me in a project a few months ago, i don't remember why):
public virtual DbSet<JumpList> JumpLists { get; set; }
public virtual DbSet<Group> Groups { get; set; }
public virtual DbSet<Item> Items { get; set; }
Also i had to use LONG instead of INT for classes ID because sqlite uses LONG as default for table ID, so after when you do a CRUD operation it fails because it can't compare/convert/cast LONG(64) to INT(32).
I'm creating an n-tier application in .NET core in which I try to keep the Identity framework out of my presentation layer as much as possible. Since I'm going to use a linux server to run my application, I'll be using Sqlite databases to persist my domain and all identity related classes.
All documentation I've encountered (official ms documentation and various blogs, tutorials ...) doesn't use SQLite.
In my datalayer I have a DbContext class which inherits from the ASP.NET's core IdentityDbContext.
public class SquiriusDbContext : IdentityDbContext<User>
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
public DbSet<Article> Articles { get; set; }
public DbSet<HtmlSection> HtmlSections { get; set; }
public DbSet<MediaSection> MediaSections { get; set; }
public DbSet<Comment> Comments { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<Tag> Tags { get; set; }
public SquiriusDbContext() { }
public SquiriusDbContext(DbContextOptions options) : base(options)
{
Database.Migrate();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var connectionStringBuilder = new SqliteConnectionStringBuilder { DataSource = "squiriusdb.db" };
var connectionString = connectionStringBuilder.ToString();
var connection = new SqliteConnection(connectionString);
optionsBuilder.UseSqlite(connection);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
When I try to perform a migration, I'm getting the following error:
PM> add-migration identity
An error occurred while calling method 'ConfigureServices' on startup class 'Startup'. Consider using IDbContextFactory to override the initialization of the DbContext at design-time. Error: GenericArguments[0], 'Squirius.Domain.Authentication.User', on 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`4[TUser,TRole,TContext,TKey]' violates the constraint of type 'TUser'.
System.InvalidOperationException: The entity type 'User' requires a primary key to be defined.
The error says that the entity type 'User' requires a primary key to be defined, which is strange since this User class inherits directly from Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser.
I think this might have something to do with the limitations of the EF7 Sqlite provider, and using an ms sql server database would solve this error.
Does anyone know a way around this so I can use an Sqlite db in order to be able to build for a linux platform?
Thanks!