EF won't create empty database - c#

I'm trying to create a database through EF, to store members and their locations.
I've had a look at other examples, but no matter what I do, when I run my program, my database doesn't get created.
I've noticed that the example I followed created a DataInitializer class, which puts some records in the database. I haven't done this yet, since I would like to check if my database gets created with the right columns.
Could not having data in the database be the problem?
public class ApplicationDbContext : DbContext
{
public DbSet<Lid> Leden { get; set; }
public DbSet<Locatie> Locaties { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.ApplyConfiguration(new LidConfiguration());
builder.ApplyConfiguration(new LocatieConfiguration());
}
}
Appsettings.json:
{ "ConnectionStrings": {
"DefaultConnection": "Server=.\\sqlexpress;Database=Taijitan;Trusted_Connection=True;MultipleActiveResultSets=true"},
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*"
}
In the example I followed, startup.cs also contains
services.AddScoped<BeerhallDataInitializer>();
and all the way at the bottom
beerhallDataInitializer.InitializeData();
I don't suppose this is what's causing the problem, but I'm not so sure anymore
EDIT:
public class BeerhallDataInitializer
{
private readonly ApplicationDbContext _dbContext;
public BeerhallDataInitializer(ApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public void InitializeData()
{
_dbContext.Database.EnsureDeleted();
if (_dbContext.Database.EnsureCreated())
{ *create new objects and add them to _dbcontext*
_dbContext.SaveChanges();
}
}

In order to run a migration you first need to create the migration with the command:
'dotnet ef migrations add InitialCreate'
Secondly, then you need to run your migration with the command:
'dotnet ef database update' or by creating some code that run missing migrations which i can assume it's what beerhallDataInitializer.InitializeData() does but can't know for sure since I have no more information about it but to be able to migrate via code you need the reference to the IApplicationBuilder like so in the startup.cs file:
DbInitializer.Migrate<ApplicationDbContext>(app);
and my dbinitilizer is :
public static class DbInitializer
{
public static void Migrate<T>(IApplicationBuilder app) where T : DbContext
{
using (var scope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
scope.ServiceProvider.GetRequiredService<T>().Database.Migrate();
}
}
}
Hope it helps anything just comment bellow but give more information about what you have done
Edit:
try changing your connection string to:
Data Source=localhost\\SQLEXPRESS;Initial Catalog=Taijitan;Integrated Security=True

Related

How do I connect a Razor Pages ASP.NET app to an already existing, not local MSSQL database?

I want to create a Razor Pages app where I would display the entries from a database. What am I supposed to put in the Connection String? I have the login to this database and the server.
And after I connect to it, how do I access it and simply display all the rows from the db in a page?
There are a few things you should consider in order to access entities from DB in Razor Pages.
Set the Connection String in appsettings.json
local:
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=XXXXXXX;Trusted_Connection=True;"
},
remote:
"ConnectionStrings": {
"DefaultConnection": "Server=xxx.xxx.xxx.xx;Database=XXXXXXX;User Id=yourUsername;password=yourPassword;Trusted_Connection=False;MultipleActiveResultSets=true;"
}
Add DB Context class that inherits DBContext ex. "YourDBContext"
public class YourDBContext: DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString);
}
}
Add DbContext to app services
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<YourDBContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}
Than you can use Dependency Injection and access entity in your page via context:
public class IndexModel : PageModel
{
YourDBContext_context;
public IndexModel(YourDBContext context)
{
_context = context;
}
public async Task<IActionResult> OnPostAsync()
{
IList<Blog> entities = await _context.Blogs.ToListAsync();
....

How to configure Entity Framework in a separate project?

I have an ASP.NET MVC application EducationalCenter with the following structure of projects:
DbContext file is EducationalCenterContext.cs in the Data project and looks as follows:
public sealed class EducationalCenterContext: DbContext
{
public DbSet<Student> Students { get; set; }
public EducationalCenterContext( DbContextOptions<EducationalCenterContext> options)
: base(options)
{
Database.EnsureCreated();
}
}
And in Startup.cs file, the dbContext configured as follows in ConfigureService():
services.AddDbContext<EducationalCenterContext>
(options => options.UseSqlServer("Server=localhost;Database=EducationalCenterDb;Trusted_Connection=True;MultipleActiveResultSets=true"));
This is my working version to which I came by fixing errors when try to add-migration. However it seems awful to me that my web app has project reference to the Data project.
What was my first idea:
In appsettings.json I created this section :
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=EducationalCenterDb;Trusted_Connection=True;MultipleActiveResultSets=true"
}
Then I created AppSettings class in the Common project:
public class AppSettings
{
public string ConnectionString { get; set; }
}
Then I try to pass ConnectionString in DAL via DI:
services.Configure<AppSettings>(Configuration.GetSection("ConnectionStrings"));
And created EducationalDbContext.cs:
public sealed class EducationalCenterContext: DbContext
{
private readonly string _connectionString;
public DbSet<Student> Students { get; set; }
public EducationalCenterContext( IOptions<AppSettings>, DbContextOptions<EducationalCenterContext> options)
: base(options)
{
_connectionString = app.Value.ConnectionString;
Database.EnsureCreated();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(_connectionString);
}
}
But when I try to add-migration via PM Console, I ran into this error:
Could not load assembly 'EducationalCenter.Data'. Ensure it is referenced by the startup project 'EducationalCenter'
Then I added project reference and ran into the next error:
Unable to create an object of type 'EducationalCenterContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
Then I added services.AddDbContext<> in Startup.cs and came to the working version which I mentioned above.
So...
Is it normal that my web app has reference to the data access project?
Is it possible to configure EF in the Data project and ensure normal separation between DAL, BLL and web app?
Putting the context and configuration in a separate project is fine.
You got the first error because "Education Center" was set as start up project but did not have reference to data project.
The second error is because the migration builder needs some connection information in the data project to resolve the connection (to compare EF state and database state) to determine what changes are needed.
First add reference in your data project to:
Microsoft.EntityFrameworkCore.Design
Then add a context factory in your data project that migration console command will discover:
internal class MyContextFactory : IDesignTimeDbContextFactory<MyContext>
{
public MyContext CreateDbContext(string[] args)
{
var dbContextBuilder = new DbContextOptionsBuilder<MyContext>();
var connString = "myconnection string";
dbContextBuilder.UseSqlServer(connString);
return new MyContext(dbContextBuilder.Options);
}
}

How to specify an Entity Framework Connection String in API Project

Question: How do I specify the Entity Framework connection string within a .NET API?
I am accustomed to creating a DAL class and specifying the base connection string like I did here.
public class LocalContext : DbContext
{
public LocalContext() : base("LocalDBContext")
{
}
public DbSet<Weapons> Weapons { get; set;
}
Which in turn grabs the LocalDBContext connection string from the web.config or appsettings.json.
"ConnectionStrings": {
"LocalDBContext": "Server=.;Database=Weapons;Trusted_Connection=True;"
},
This is what I have done in the past in various web apps but not sure if I have to do something different with an API?
I would expect it to call and save into "Weapons" at "Server=." however it instead created a new Database called "LocalDBContext" at the connection of "(localdb)\mssqllocaldb". Any tips would be greatly appreciated!
In EF core you don't need to send a connection to the base class with the constructor, just follow this approach:
public partial class LocalContext : DbContext
{
public LocalContext ()
{
}
public LocalContext(DbContextOptions<LocalContext> options) :
base(options)
{
}
public virtual DbSet<Weapon> Weapons { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
//warning You can move this code to protect potentially sensitive
information
//in connection string.
optionsBuilder.UseSqlServer("Data Source= .;Initial
Catalog=Weapons;Trusted_Connection=True;");
}
}
}
The given String "LocalDBContext" is interpreted as Connectionstring, see official Documentation on DbContext(String).
Do something like:
public class LocalContext : DbContext
{
public LocalContext (DbContextOptions<LocalContext> options)
: base(options)
{
}
....
I have some questions below:
Questions:
Did you add Entity data model in your API solution?
If yes, didn't you save connection string in config file while adding EDM?
While adding EDMX in solution, model window asks to connect the database. Once EDM connects with database, it asks to save connection string in configuration file. You can add tables, functions, SPs, views. This way EDM connects with actual database rather picking different database.

No parameterless constructor was found on 'TContext'

I am not really clear on why the error happens. When I first scaffold my project the migration and update-database commands ran fine but after few changes in the application I was getting this error. The only solution floating around is this:
public class BloggingContextFactory : IDbContextFactory<BloggingContext>
{
public BloggingContext Create()
{
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlite("Data Source=blog.db");
return new BloggingContext(optionsBuilder.Options);
}
}
My DbContext:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IApplicationDbContext
{
public DbSet<ApplicationUserCode> ApplicationUserCodes { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
}
It works for me but the connection string is hard-coded inside the class which is not fine with me. Any clarifications as to why this error did not happen at one time and later it did is really appreciated and also a elegant solution than embedding connection string in class please.
did you have this
public class BloggingContext : DbContext
{
public BloggingContext(){ // << The reason....
}
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{ }
public DbSet<Blog> Blogs { get; set; }
}
Another reason is that it was seeing the OnModelCreating(ModelBuilder builder){} override without the base.OnModelCreating(builder); call inside the OnModelCreating(){} method at the top of the method itself. Threw me for a loop as to why... then I tried a few things, low and behold it was a simple inclusion of the parameterless constructor it was looking was the culprit.
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder); //<< Absolutely required at the top.
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
EDIT
//Startup.cs ConfigureServices(IServiceCollection services)
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(Configuration.GetConnectionString("SqliteConnection")));
//appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Data Source=(LocalDb)\\MssqlLocalDb;Initial Catalog=PilotSystemCore;Integrated Security=True",
"SqliteConnection" : "Data Source=SqliteDbName.db"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
NB: If you did any migrations with SqlServer before, the generated items are long valid redo the migrations.

Seed method not called, Entity Framework 6

I have a DatabaseInitializer class
public class DatabaseInitializer : CreateDatabaseIfNotExists<DatabaseContext>
{
protected override void Seed
(
DatabaseContext databaseContext
)
{
// Seed the hash methods.
var defaultHashMethod = new HashMethod
{
Description = "Default",
CreateDate = DateTime.Now
};
databaseContext.HashMethod.Add(defaultHashMethod);
databaseContext.SaveChanges();
}
}
In my DatabaseContext class I set the initializer
public DatabaseContext() : base("DatabaseContext")
{
InitializeDatabase();
}
private void InitializeDatabase()
{
Database.SetInitializer(new DatabaseInitializer());
if (!Database.Exists())
{
Database.Initialize(true);
}
}
As far as I can understand the seed method is only invoked once you perform an operation such as a query. My database is created successfully and I'm querying the table, but the seed method is never called.
Update:
It seems like the problem is caused because of a class that is inheriting from my DatabaseContext class, when using this class to perform database operations, the seed method is not called. When using my DatabaseContext class, everything works as expected
public DbSet<TestEntity> TestEntity { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
You need to call Update-Database from the Package Manager Console.
The only way I could get this to work was to call the seed method myself
Here are the methods for my DatabaseContext class
public DatabaseContext() : base("DatabaseContext")
{
InitializeDatabase();
}
public DatabaseContext(string connectionString) : base(connectionString)
{
Database.Connection.ConnectionString = connectionString;
InitializeDatabase();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
Here I changed my InitializeDatabase method from
private void InitializeDatabase()
{
Database.SetInitializer(new DatabaseInitializer());
if (!Database.Exists())
{
Database.Initialize(true);
}
}
to
protected virtual void InitializeDatabase()
{
if (!Database.Exists())
{
Database.Initialize(true);
new DatabaseInitializer().Seed(this);
}
}
This can happen if your Update-Database command does not run successfully, and this does not necessarily mean that it errors out. There might be changes that EF recognizes as "outstanding" that need to be added to a migration.
Try calling "Add-Migration {migrationNameHere}" and then try "Update-Database" again.
to get Seed method to be called when you are not using AutomaticMigration, you should use MigrateDatabaseToLatestVersion initializer for your code-first database.
like this:
Database.SetInitializer(new MigrateDatabaseToLatestVersion<YourContext,YourConfiguration>());
this way, Seed method will be called every time the migration is done successfully.
I had this issue and the problem was my Context constructor did not use the same name as in my web.config.
If you are using Code-First then you can populate the data when the application runs for the first time.
Create a DbInitializer
public class MyDbInitializer : IDatabaseInitializer<MyDbContext>
{
public void InitializeDatabase(MyDbContext context)
{
if (context.Database.Exists())
{
if (!context.Database.CompatibleWithModel(true))
{
context.Database.Delete();
}
}
context.Database.Create();
User myUser = new User()
{
Email = "a#b.com",
Password = "secure-password"
};
context.Users.AddOrUpdate<User>(p => p.Email, myUser);
context.SaveChanges();
}
}
Register this DbInitializer in your Global.asax.cs Application_Start method
Database.SetInitializer(new My.namespace.MyDbInitializer());
My seed was not being executed either. However, it was because I added a column to a model that I had no intention of using in my actual database and forgot to use the [NotMapped] annotation.
[NotMapped]
public string Pair { get; set; }
There was no error message relating to this being the cause at all. Just a null reference to my repository obj when I tried to query data that should have been there.

Categories

Resources