EF Core Query Custom IdentiyUser - c#

I am still relatively new to EF Core and beforehand I used PetaPoco, so please forgive my ignorance. In my database, I added the following fields to my AspNetUsers table:
Elevated
Deactivated
FirstName
LastName
I then created the following classes following this blog article:
public partial class ApplicationUser : IdentityUser
{
public bool? Deactivated { get; set; }
public bool? Elevated { get; set; }
[StringLength(255)]
public string FirstName { get; set; }
[StringLength(255)]
public string LastName { get; set; }
}
and
public class ApplicationClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>
{
public ApplicationClaimsPrincipalFactory(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager, IOptions<IdentityOptions> optionsAccessor) : base(userManager, roleManager, optionsAccessor)
{ }
public override async Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
{
var principal = await base.CreateAsync(user);
if (!string.IsNullOrWhiteSpace(user.FirstName))
{
((ClaimsIdentity)principal.Identity).AddClaims(new[] {
new Claim(ClaimTypes.GivenName, user.FirstName)
});
}
if (!string.IsNullOrWhiteSpace(user.LastName))
{
((ClaimsIdentity)principal.Identity).AddClaims(new[] {
new Claim(ClaimTypes.Surname, user.LastName)
});
}
return principal;
}
}
I also setup the AddIdentity and AddScoped methods too in my Startup.cs file.
What I do not understand going forward from this point is how to query the table, returning my custom properties. In my controller, I want to do something like this:
/// <summary>
/// Gets every User.
/// </summary>
/// <returns>HTTP Result</returns>
[HttpGet]
[Route("")]
public async Task<ActionResult<IEnumerable<ApplicationUser>>> GetUsers()
{
var users = await this._context.Users.Select(user => new
{
user.Id,
user.Decativated,
user.Elevated,
user.Email,
user.FirstName,
user.LastName
}).ToListAsync();
return Ok(users);
}
But obviously I can't because the properties don't exist on the Users DbSet.
So long story short, I think that I have everything setup properly but how do I actually query my extended IdentityUser?
EDIT
As requested, the following is my DbContext. I only have a dummy table wired up right now as I was just trying to get the extensions on the AspNetUsers table working first:
public partial class [removed for confidentiality]Context : IdentityDbContext
{
public [removed for confidentiality]Context()
{
}
public [removed for confidentiality]Context(DbContextOptions<[removed for confidentiality]Context> options)
: base(options)
{
}
public virtual DbSet<Foo> Foos { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasAnnotation("ProductVersion", "[removed for confidentiality]");
modelBuilder.Entity<Foo>(entity =>
{
entity.Property(e => e.FooName).IsUnicode(false);
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}

You have to specify type parameter(s) for IdentityDbContext. You need to inherit from IdentityDbContext<TUser> class. Without type parameters you are using classes defined in ASP.NET Core Identity. Everything you'd like to change must be reflected in your code.
public partial class [removed for confidentiality]Context : IdentityDbContext<ApplicationUser>
{
public [removed for confidentiality]Context()
{
}
public [removed for confidentiality]Context(DbContextOptions<[removed for confidentiality]Context> options)
: base(options)
{
}
public virtual DbSet<Foo> Foos { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasAnnotation("ProductVersion", "[removed for confidentiality]");
modelBuilder.Entity<Foo>(entity =>
{
entity.Property(e => e.FooName).IsUnicode(false);
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}

Related

EF Core: Multiple DbContext with one Database

I am trying to rekindle this topic. It was once started over 10 years ago, and while there were some comments that are a couple years ago, it has now been closed. Yet again, this still is kind of unclear to me.
A lot of people put their opinions on it, and whilist there were some good reasons and opinions, the practical approach, and overall conclusion is still unclear, at least to me.
My situation: I am trying to create a way more complicated than neccesary app to research and test things. I've been using only one DbContext up until now and now I wish to separate it by creating a new one for identity/security (I am aware that IdentityDbContext exists, and while this is a smarter solution, I wanna play around).
As I managed to configure the second DbContext and create a migration, the migration state has been resetted to "Initial" and new tables are created (instead of using the old ones).
My question: What is a good practical example where introduction of the new DbContext is applied and how to replicate the up until now Migration Snapshot to it (in order to continue the sequence). Also, to replicate the future state of Migration Snapshot to the original DbContext and so on.
Here are some code examples that I managed to scribble:
This is a part of the base class extension for DbContexts.
public class DbContextExtend : DbContext
{
protected readonly ICurrentUserService _userService;
protected readonly IDateTime _dateTime;
public DbContextExtend(DbContextOptions<ReservationDbContext> options) : base(options) { }
public DbContextExtend(DbContextOptions<ReservationDbContext> options,
IDateTime datetime,
ICurrentUserService userService) : base(options)
{
_dateTime = datetime;
_userService = userService;
}
public DbContextExtend(DbContextOptions<SecurityDbContext> options) : base(options) { }
public DbContextExtend(DbContextOptions<SecurityDbContext> options,
IDateTime datetime,
ICurrentUserService userService) : base(options)
{
_dateTime = datetime;
_userService = userService;
}
public DbSet<Audit> Audits { get; set; }
public async override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
//var auditEntries = await OnBeforeSaveChangesAsync();
var result = await base.SaveChangesAsync(cancellationToken);
//await OnAfterSaveChanges(auditEntries);
return result;
}
}
A freshly introduced DbContext - OnModelCreating, Ignore Reservations and everything after it in order to focus on the 3 tables of importance (is there a better way to do this).
public class SecurityDbContext : DbContextExtend, ISecurityDbContext
{
public SecurityDbContext(DbContextOptions<SecurityDbContext> options) : base(options) { }
public SecurityDbContext(DbContextOptions<SecurityDbContext> options,
IDateTime datetime,
ICurrentUserService userService) : base(options, datetime, userService) { }
public DbSet<User> Users { get; set; }
public DbSet<LoginDetails> LoginDetails { get; set; }
public DbSet<Role> Roles { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfiguration(new Configurations.SecurityConfiguration.RoleConfiguration());
modelBuilder.ApplyConfiguration(new Configurations.SecurityConfiguration.UserConfiguration());
modelBuilder.ApplyConfiguration(new Configurations.SecurityConfiguration.LoginDetailsConfiguration());
modelBuilder.Ignore<Reservation>();
}
}
The DbContext that was in use up untill now. Ignoring the table that should be out of it, the LoginDetails.
public class ReservationDbContext : DbContextExtend, IReservationDbContext
{
public ReservationDbContext(DbContextOptions<ReservationDbContext> options) : base(options) { }
public ReservationDbContext(DbContextOptions<ReservationDbContext> options,
IDateTime datetime,
ICurrentUserService userService) : base(options, datetime, userService) { }
public DbSet<Role> Roles { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<LoginDetails> LoginDetails { get; set; }
public DbSet<EventType> EventTypes { get; set; }
public DbSet<Event> Events { get; set; }
public DbSet<Question> Questions { get; set; }
public DbSet<EventQuestion> EventQuestions { get; set; }
public DbSet<EventOccurrence> EventOccurrences { get; set; }
public DbSet<Ticket> Tickets { get; set; }
public DbSet<Reservation> Reservations { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfiguration(new EventTypeConfiguration());
modelBuilder.ApplyConfiguration(new EventConfiguration());
modelBuilder.ApplyConfiguration(new QuestionConfiguration());
modelBuilder.ApplyConfiguration(new EventOccuranceConfiguration());
modelBuilder.ApplyConfiguration(new ReservationConfiguration());
modelBuilder.ApplyConfiguration(new TicketConfiguration());
modelBuilder.ApplyConfiguration(new UserConfiguration());
modelBuilder.ApplyConfiguration(new RoleConfiguration());
modelBuilder.Ignore<LoginDetails>();
}
}
UserConfiguration - an example of a configuration and it is a table that separates both contexts (but is contained in both).
public class UserConfiguration : AuditableEntityConfiguration<User>
{
public override void ConfigureAuditableEntity(EntityTypeBuilder<User> builder)
{
builder.HasKey(u => u.Id);
builder.Property(u => u.Email)
.HasMaxLength(128)
.IsRequired();
builder.Property(u => u.Name)
.IsRequired();
builder.Property(u => u.PhoneNumber)
.HasMaxLength(20)
.IsRequired(false);;
builder.Property(u => u.RoleId)
.IsRequired();
builder.HasOne(u => u.Role)
.WithMany(r => r.Users)
.HasForeignKey(u => u.RoleId);
builder.HasOne(u => u.LoginDetails)
.WithOne(ld => ld.User)
.HasForeignKey<LoginDetails>(u => u.UserId)
.IsRequired();
}
}
It might be worth noting that I also decided to separated SecurityDbContext logic to a different project.
Please feel free to give me all advice and real world experience that you can. I would greatly appreciate it!
You should generate different migration for each DbContext. If you have different entities that you want to be in the same db table, explicitly say that in each configuration, using the ToTable() method. Also, their configuration should match. Finally, you should also be explicit about the db name, so in each OnModelCreating you should pass in the builder.HasDefaultScheme() the same value.
Let's say i have an IdentityDbContext that inherits from the IdentityDbContext<>, the default that you get in asp, but with an AppUser that inherits from the IdentityUser, so i have a configuration for that. Then i would have something like that:
public class IdentityDbContext : IdentityDbContext<AppUser>
{
//Other stuff
protected override void OnModelCreating(ModelBuilder builder)
{
builder.HasDefaultSchema("TestDb");
builder.ApplyConfiguration(new AppUserConfiguration())
base.OnModelCreating(builder);
}
}
Then i have a WriteDbContext that inherits from the DbContext, and i have a configuration for a customer:
public class WriteDbContext : DbContext
{
public DbSet<Customer> Customers { get; set; }
//Other stuff
protected override void OnModelCreating(ModelBuilder builder)
{
builder.HasDefaultSchema("TestDb");
builder.ApplyConfiguration(new CustomerConfiguration())
base.OnModelCreating(builder);
}
}
At that point i need to generate a migration for each DbContext and then apply them. Then i would have all the identity stuff and the customer in the same Database.
I could also have a CustomerReadModel that i can use only for reads, so it does not have any logic, private fields and maybe has navigation to other ReadModels. As long as they all have the same configuration, for example the FirstName in both of them is configured to be nvarchar(50), if the customer has one Address (as an entity), then the CustomerReadModel has also one or it has a AddressReadModel configured as the Address etc, and in both configuration i have builder.ToTable("Customers") the will both point to the same customers db table:
public class ReadDbContext: DbContext
{
public DbSet<CustomerReadModel> Customers{ get; set; }
//Other stuff
protected override void OnModelCreating(ModelBuilder builder)
{
builder.HasDefaultSchema("TestDb");
builder.ApplyConfiguration(new CustomerReadModelConfiguration())
base.OnModelCreating(builder);
}
}
And i now should not add a migration for the ReadDbContext, since the database is already configured.
You can also check these out if you want (disclaimer: they are mine):
https://www.youtube.com/watch?v=QkHfBNPvLms
https://www.youtube.com/watch?v=MNtXz4WvclQ
Edit : I made a demo some time ago that has some of the above: https://github.com/spyroskatsios/MakeYourBusinessGreen

DbContext error when using it for ActionFilter in ASP.NET Core MVC

I need to log certain user actions, such as Login, logout, CRUD, etc. and save to a table called AuditRecords. I have a DbContext called AuditContext:
I have learned that applying an ActionFilter and decorate a controllermethod with it is the way to go. The AuditContext is causing a red squiggly asking for the 'options', which baffles me. I have tried DI, but got the same results. Any thoughts? I am on DotNet 5.01, but I tried it withg DotNet 6 as well with the same results.
EDIT
I changed the AuditAttribute and Context to make it as straightforward as possible and by using Dependency Injection, as advised. But the problem is still not solved.
public class Audit
{
//Audit Properties
public Guid AuditID { get; set; }
public string UserName { get; set; }
public string IPAddress { get; set; }
public string AreaAccessed { get; set; }
public DateTime Timestamp { get; set; }
//Default Constructor
public Audit() { }
}
public class AuditContext : DbContext
{
public DbSet<Audit> AuditRecords { get; set; }
}
public class HomeController : Controller
{
//red squiggly under [Audit] decoration with error of no formal
//parameter 'context' in AuditAttribute.AuditAttribute(AuditContext)
[Audit]
public IActionResult Privacy()
{
return View();
}
//AuditAttribute class
using Microsoft.AspNetCore.Mvc.Filters;
using System;
namespace LoggingDemoMVC.Filters
{
public class AuditAttribute : ActionFilterAttribute
{
private readonly AuditContext _context;
public AuditAttribute(AuditContext context)
{
_context = context;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//Stores the Request in an Accessible object
var request = filterContext.HttpContext.Request;
//Generate an audit
Audit audit = new Audit()
{
//Your Audit Identifier
AuditID = Guid.NewGuid(),
//Our Username (if available)
UserName = (filterContext.HttpContext.User.Identity.IsAuthenticated) ? filterContext.HttpContext.User.Identity.Name : "Anonymous",
//The IP Address of the Request
IPAddress = request.Path,
//The URL that was accessed
AreaAccessed = request.HttpContext.Request.Path,
//Creates our Timestamp
Timestamp = DateTime.UtcNow
};
//Stores the Audit in the Database
_context.AuditRecords.Add(audit);
_context.SaveChanges();
//Finishes executing the Action as normal
base.OnActionExecuting(filterContext);
}
}
}
WebAppContext expects a DbContext<WebAppContext> to be passed into its constructor . However , you are calling the constructor without providing anything :
WebAppContext _context = new WebAppContext()
To fix the issue , you can just plug into the Dependency Injection system that you've set up
public class CustomFilter : IActionFilter
{
private readonly WebAppContext _context;
public CustomFilter(WebAppContext context)
{
_context = context;
}
public void OnActionExecuting(ActionExecutingContext context)
{
//.......
_context.AuditRecords.Add(...);
_context.SaveChanges();
}
}
Simple Demo :
model
public class Audit
{
public int ID { get; set; }
public string Name { get; set; }
}
DataContext
public class WebAppContext : DbContext
{
public WebAppContext(DbContextOptions<WebAppContext> options) : base(options)
{
}
public DbSet<Audit> AuditRecords { get; set; }
}
Custom Filter
public class CustomFilter :Attribute,IActionFilter
{
private readonly WebAppContext _context;
public CustomFilter(WebAppContext context)
{
_context = context;
}
public void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine("end");
}
public void OnActionExecuting(ActionExecutingContext context)
{
Audit audit = new Audit();
audit.Name = "mike";
_context.AuditRecords.Add(audit);
_context.SaveChanges();
}
}
Startup
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
//config database
services.AddDbContext<WebAppContext>(option=>option.UseSqlServer(Configuration.GetConnectionString("default")));
//add filter
services.AddScoped<CustomFilter>();
}
controller
[TypeFilter(typeof(CustomFilter))]
public IActionResult Privacy()
{
return View();
}
when I access Privacy method , The database will add a row of data
First, add the Nuget package Microsoft.EntityFrameworkCore.SqlServer to your project.
Then, add the following code to the ConfigureServices method of your Startup class:
services.AddDbContext<WebAppContext>(options =>
options.UseSqlServer("[your connectionstring here]"));
That's the bare minimum and this will enable you to inject the DbContext into the ActionFilter.

The entity type was not found. Ensure that the entity type has been added to the model

I'm new to ASP.NET Core and i'm trying to insert an entity into an Entity Framework Core model scaffolded from a simple existing MariaDB database.
This is the entity model:
public class ScrapeAsincroni
{
public int Id { get; set; }
public string Paese { get; set; }
public string Engine { get; set; }
public string Keywords { get; set; }
}
This is the controller action that is supposed to add the entity:
public JsonResult create(string paese, string engine, string keywords)
{
ScrapeAsincroni scrapeAsincrono = new ScrapeAsincroni {
Paese = paese,
Engine = engine,
Keywords = keywords
};
_context.Add(scrapeAsincrono);
try
{
_context.SaveChangesAsync();
}
catch (Exception ex)
{
return Json(new Dictionary<string, int?> { { "id", null } });
}
return Json(new Dictionary<string, int?>{ {"id", scrapeAsincrono.Id} });
}
The database context (_context) has been initialized on the controller's constructor.
the line
_context.Add(scrapeAsincrono);
throws the following exception:
System.InvalidOperationException: The entity type 'ScrapeAsincroni' was not found. Ensure that the entity type has been added to the model.
This is the modelBuilder code relative to this model
public partial class ScraperDbContext : DbContext
{
public ScraperDbContext()
{
}
public ScraperDbContext(DbContextOptions<ScraperDbContext> options)
: base(options)
{
}
public virtual DbSet<ScrapeAsincroni> ScrapeAsincroni { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
optionsBuilder.UseMySql("server=#.#.#.#;port=####;user=####;password=####;database=####", x => x.ServerVersion("10.3.25-mariadb"));
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ScrapeAsincroni>(entity =>
{
entity.HasComment("Informazioni su una ricerca asincrona dello Scraper");
entity.Property(e => e.Id)
.HasColumnName("id")
.HasColumnType("int(11)");
entity.Property(e => e.Engine)
.HasColumnName("engine")
.HasColumnType("varchar(255)")
.HasCharSet("utf8")
.HasCollation("utf8_general_ci");
entity.Property(e => e.Keywords)
.IsRequired()
.HasColumnName("keywords")
.HasColumnType("text")
.HasCharSet("utf8")
.HasCollation("utf8_general_ci");
entity.Property(e => e.Paese)
.HasColumnName("paese")
.HasColumnType("varchar(255)")
.HasCharSet("utf8")
.HasCollation("utf8_general_ci");
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
I can't seem to understand why this happens, and couldn't find any solutions online.
add
public DbSet<ScrapeAsincroni> ScrapeAsincronis { get; set; }
in your context file for adding an entity to your model.
It was, of course, a trivial error that i would fix the next day. I was using the base DbContext class, while i should have used the custom database context class which i defined when scaffolding the database.
This is how the context was instantiated before in the controller script:
private readonly DbContext _context;
public ScrapeAsincroniController(DbContext context)
{
_context = context;
}
now it is:
private readonly ScraperDbContext _context;
public ScrapeAsincroniController(ScraperDbContext context)
{
_context = context;
}
I also changed this line in startup.cs:
services.AddDbContext<ScraperDbContext>(options => options
.UseMySql("<your_connection_string>",
mysqlOptions => mysqlOptions.ServerVersion(new Pomelo.EntityFrameworkCore.MySql.Storage.ServerVersion(new Version(10, 3, 25), ServerType.MariaDb))
)
);

Database Schema not changing at Runtime in Asp.net Core 2.2 & Entity Framework Core

i had an application where data is saved in different sql schema for different Users.
For e.g.
User 1 Data is saved in SCHEMA1
User 2 Data is saved in SCHEMA2
Previously application was developed in MVC 3 and it is working fine and as expected.
Now we are migrating application in .Net Core 2.2 in which this fucntionality is not working
.net core does not have IDbModelCacheKeyProvider due to this only one schema is working
Below is the DBContext File
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
//public string Schema { get; set; }
private readonly IConfiguration configuration;
public string SchemaName { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public ApplicationDbContext(string schemaname)
: base()
{
SchemaName = schemaname;
}
public DbSet<EmployeeDetail> EmployeeDetail { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json");
var configuration = builder.Build();
optionsBuilder.UseSqlServer(configuration["ConnectionStrings:SchemaDBConnection"]);
var serviceProvider = new ServiceCollection().AddEntityFrameworkSqlServer()
.AddTransient<IModelCustomizer, SchemaContextCustomize>()
.BuildServiceProvider();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.RemovePluralizingTableNameConvention();
modelBuilder.HasDefaultSchema(SchemaName);
base.OnModelCreating(modelBuilder);
}
public string CacheKey
{
get { return SchemaName; }
}
}
public class SchemaContextCustomize : ModelCustomizer
{
public SchemaContextCustomize(ModelCustomizerDependencies dependencies)
: base(dependencies)
{
}
public override void Customize(ModelBuilder modelBuilder, DbContext dbContext)
{
base.Customize(modelBuilder, dbContext);
string schemaName = (dbContext as ApplicationDbContext).SchemaName;
(dbContext as ApplicationDbContext).SchemaName = schemaName;
}
}
My question is how to change schemaName at runtime
So what is the right way to organize that mechanism:
Figure out the schema name by the user credentials;
Get user-specific data from database from specific schema.
I was able to change schema at runtime by changing onConfiguring Method
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public string SchemaName { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public ApplicationDbContext(string schemaname)
: base()
{
SchemaName = schemaname;
}
public DbSet<EmployeeDetail> EmployeeDetail { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json");
var configuration = builder.Build();
var serviceProvider = new ServiceCollection().AddEntityFrameworkSqlServer()
.AddSingleton<IModelCustomizer, SchemaContextCustomize>()
.BuildServiceProvider();
optionsBuilder.UseSqlServer(configuration["ConnectionStrings:SchemaDBConnection"]).UseInternalServiceProvider(serviceProvider);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// modelBuilder.MapProduct(SchemaName);
modelBuilder.RemovePluralizingTableNameConvention();
if (!string.IsNullOrEmpty(SchemaName))
{
modelBuilder.HasDefaultSchema(SchemaName);
}
base.OnModelCreating(modelBuilder);
}
public string CacheKey
{
get { return SchemaName; }
}
public class SchemaContextCustomize : ModelCustomizer
{
public SchemaContextCustomize(ModelCustomizerDependencies dependencies)
: base(dependencies)
{
}
public override void Customize(ModelBuilder modelBuilder, DbContext dbContext)
{
base.Customize(modelBuilder, dbContext);
string schemaName = (dbContext as ApplicationDbContext).SchemaName;
(dbContext as ApplicationDbContext).SchemaName = schemaName;
}
}
}
The best way is to use Multi-Tenancy Architecture to be able to use database schema per user ( Tenant )
This architecture is recommended for Saas appllications
Concepts
Let’s agree on some basic concepts:
We use a tenant identification (or resolution) strategy to find out what tenant are we talking to
A tenant DbContext access strategy will figure out the way to retrieve (and store)
This article will show you how to implement Multi-tenancy app using .net core : https://stackify.com/writing-multitenant-asp-net-core-applications/

There is already an object named'' in the database entity framework

I have a DbContext like this,
public class EPDContext : TrackerContext
{
public EPDContext()
: base("name=DevelopmentApplicationServices")
{
Database.SetInitializer<EPDContext>(new EPDDBInitializer());
this.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
}
public DbSet<TaskRevision> TaskRevisions { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<TaskRevision>().HasMany(x => x.Models).WithMany().Map(x => x.MapLeftKey("TaskRevisionID").MapRightKey("ModelId").ToTable("TaskRevision2Models"));
}
}
public class EPDDBInitializer : CreateDatabaseIfNotExists<EPDContext>
{
protected override void Seed(EPDContext context)
{
//// My Seeding data goes here
base.Seed(context);
}
}
And my Entity:
[TrackChanges]
public class TaskRevision
{
#region properties
[Key]
public Guid TaskRevisionID { get; set; }
public virtual List<Model> Models { get; set; }
}
and my migration configuration class looks like:
internal sealed class Configuration : DbMigrationsConfiguration<PW.EPD.Data.EPDContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
}
protected override void Seed(PW.EPD.Data.EPDContext context)
{
}
}
I got this error "There is already an object named 'TaskRevisions' in the database entity framework." when I execute my application. DB has created successfully and there is no seeding data.
At the same time when I execute the same code after removing the onModelCreating() override method, db has created with seed data.
What I did wrong here, kindly correct me.
Thanks in advance

Categories