EF 6 - Invalid column name 'Discriminator', two DbContexts - entity-framework

I have an MVC 5 app. I would like to use the standard aspnet.identity provider to enable user login through the standard \Account views. However, I also need to connect to a third-party database and want to use EF code-first for this too.
The context for my main database I took from a Scott Allen Pluralsight. I don't know why or what the "ApplicationUser" class is doing inheriting from the IdentityUser but it worked in his video and with a previous website I created. It looks as follows:
namespace ESBAMPortal.DataLayer
{
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser
{
}
class PortalContext : IdentityDbContext<ApplicationUser>, ESBAMPortal.DataLayer.IPortalContext
{
public PortalContext()
: base("ESBamPortalConString")
{
this.Configuration.LazyLoadingEnabled = false;
}
public virtual DbSet<DomainClasses.Portal> Portal {get; set;}
}
}
The context for the third-party database is as follows:
namespace ESBAMPortal.DataLayer
{
public class ESBContext : DbContext, ESBAMPortal.DataLayer.IESBContext
{
public ESBContext()
: base("ESBExceptionConString")
{
this.Configuration.LazyLoadingEnabled = false;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
public virtual DbSet<ActionType> ActionTypes { get; set; }
public virtual DbSet<Alert> Alerts { get; set; }
public virtual DbSet<AlertCondition> AlertConditions { get; set; }
public virtual DbSet<AlertEmail> AlertEmails { get; set; }
public virtual DbSet<AlertHistory> AlertHistories { get; set; }
public virtual DbSet<AlertSubscription> AlertSubscriptions { get; set; }
public virtual DbSet<AlertSubscriptionHistory> AlertSubscriptionHistories { get; set; }
public virtual DbSet<AuditLog> AuditLogs { get; set; }
public virtual DbSet<AuditLogMessageData> AuditLogMessageDatas { get; set; }
public virtual DbSet<Batch> Batches { get; set; }
public virtual DbSet<Configuration> Configurations { get; set; }
public virtual DbSet<ContextProperty> ContextProperties { get; set; }
public virtual DbSet<Fault> Faults { get; set; }
public virtual DbSet<Message> Messages { get; set; }
public virtual DbSet<MessageData> MessageDatas { get; set; }
public virtual DbSet<ProcessedFault> ProcessedFaults { get; set; }
public virtual DbSet<UserSetting> UserSettings { get; set; }
}
}
When I run the website I am able to pull data from the third-party website ok. However, when I try to login I receive the message:
Invalid column name 'Discriminator'
This is thrown as a result of making the call:
var user = await UserManager.FindAsync(model.UserName, model.Password);
Running EF Profiler I can see that it's attempting to execute the following SQL:
SELECT [Limit1].[C1] AS [C1],
[Limit1].[Id] AS [Id],
[Limit1].[UserName] AS [UserName],
[Limit1].[PasswordHash] AS [PasswordHash],
[Limit1].[SecurityStamp] AS [SecurityStamp]
FROM (SELECT TOP (1) [Extent1].[Id] AS [Id],
[Extent1].[UserName] AS [UserName],
[Extent1].[PasswordHash] AS [PasswordHash],
[Extent1].[SecurityStamp] AS [SecurityStamp],
'0X0X' AS [C1]
FROM [dbo].[AspNetUsers] AS [Extent1]
WHERE ([Extent1].[Discriminator] = N'ApplicationUser')
AND ((((UPPER([Extent1].[UserName])) = (UPPER('rob' /* #p__linq__0 */)))
AND (NOT ((UPPER([Extent1].[UserName]) IS NULL)
OR (UPPER('rob' /* #p__linq__0 */) IS NULL))))
OR ((UPPER([Extent1].[UserName]) IS NULL)
AND (UPPER('rob' /* #p__linq__0 */) IS NULL)))) AS [Limit1]
Problem is, the AspNetUsersTable has no discriminator column.
Could anyone please explain where I've gone wrong and how I should fix?

I went back to basics, created a new MVC 5 app then generated a db migrations by running the following from the package manager console:
enable-migrations
add-migration 'first
When I inspected the code that was generated I could see that it included a "Discriminator" column in the AspNetUsers table.
I went back to my "real" solution and compared, the 'first' migration code from my separate DataAccess project. This code didn't have a "Discriminator" column, I also noticed that it had additional columns such as "PhoneNumber" and "TwoFactorEnabled". This made me think that perhaps the MVC5 template was using a previous version of "Microsoft.AspNet.Identity.EntityFramework" - this turned out the be the case.
To resolve I went to the Manage Nuget Packages dialog of the MVC5 web app, uninstalled "Microsoft.AspNet.Identity.EntityFramework"(v1.0) then re-installed (v2.0). Subsequently when I ran login from the website it no tried to find a "discriminator" column and everything worked great.
I guess this has taught me a valuable lesson to pay more attention to the versions on Nuget packages that are used by VS Templates

because the ASP.NET MVC project has a "ApplicationUser" class that already overrides IdentityUser it adds the Discriminator column to the entity framework for you automatically.
Try to drop the data base and rerun. again.
Check this http://forums.asp.net/t/1970682.aspx?ASP+NET+Identity+V2+Discriminator+Column

This happen for me when i was adding two classes inherited from IdentityDbContext if so add Discriminator to AspNetRoles
AddColumn("dbo.AspNetRoles", "Discriminator", c => c.String(nullable: false, maxLength: 128));

Try to drop the data base and rerun. again
Check this question
1. http://forums.asp.net/t/1970682.aspx?ASP+NET+Identity+V2+Discriminator+Column.http://
Also check this blogs.msdn.com/b/webdev/archive/2013/10/16/customizing-profile-information-in-asp-net-identity-in-vs-2013-templates.aspx

Related

Fetch data from multiple related tables using Entity Framework core and display in view in Asp.Net Core

I am working on one Asp.Net Core application using Entity Framework Core. That app is basically into E Commerce. I want to fetch information of particular product from multiple tables which are related to each other using the master table product, and then i want to pass the data to the View. Can anyone help me in this regard. I am unable to find any perfect solution of Joins and pass the related data to View.
To complete these steps you need Visual Studio 2022.
Based on current documentation:
public class OrderDetail
{
public int OrderDetailID { get; set; }
public int OrderID { get; set; }
public int ProductID { get; set; }
public int Quantity { get; set; }
public Order Order { get; set; }
}
public class Order
{
public int OrderID { get; set; }
public int CustomerID { get; set; }
public int EmployeeID { get; set; }
public DateTime OrderDate { get; set; }
public List<OrderDetail> OrderDetails { get; set; }
}
It is a very simple model which contains only two classes, Order and OrderDetail has a one-to-many relationship. The next step is to add a new context class and make sure to inherit from the DbContext class
public class MyContext : DbContext
{
public DbSet<OrderDetail> OrderDetails { get; set; }
public DbSet<Order> Orders { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(#"Data Source=(localdb)\ProjectsV13;Initial Catalog=StoreDB;");
}
}
Now to create a database using migrations from your model, install the following packages;
Microsoft.EntityFrameworkCore.Tools
Microsoft.EntityFrameworkCore.Design
Once these packages are installed, run the following command in Package Manager Console.
Add-Migration Initial
This command scaffold a migration to create the initial set of tables for your model. When it is executed successfully, then run the following command.
Update-Database to apply the new migration to the database. This command creates the database before applying migrations.
If you need to learn how to set up relationships the following websites have very good documentation and walkthrough on the entity framework.
I hope the following links help:
https://entityframeworkcore.com
https://www.learnentityframeworkcore.com

Many to Many relationship in Asp.Net MVC 5 with Identity table and Custom table

I'm trying to make a relationship between the Users from the table generated by Asp.Net Identity with my own table. The relationship must be many to many, since many Users can work on the same Task (which is my table), and same time an User can work on multiple Tasks.
public class Task
{
public int ID { get; set; }
public string Name { get; set; }
public string UserID { get; set; }
public virtual ICollection<ApplicationUser> Users { get; set; }
}
public class ApplicationUser : IdentityUser
{
public int TaskID { get; set; }
public virtual ICollection<Task> Tasks{ get; set; }
// rest of the code
}
I try it this way but I get an error during migration (or run time)
"One or more validation errors were detected during model generation:"
Please help me solve this problem and archive what I need.
Try it like this:
public class Projects
{
public Projects()
{
ApplicationUser = new HashSet<ApplicationUser>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ApplicationUser> ApplicationUser { get; set; }
}
Application User
public class ApplicationUser : IdentityUser
{
public ApplicationUser()
{
Projects = new HashSet<Projects>();
}
public async Task GenerateUserIdentityAsync(UserManager manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
public virtual ICollection <Projects > Projects { get; set; }
}
Application Context :
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public virtual DbSet<Projects> Projects { get; set; }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
now when I run this Mvc app and register, the db tables I get is like the following:
and the correct schema:
The things to be questioned are a lot, from my point of view important is to determine if you:
- can/should you mix application context and your model context ?
You can try it as shown below using Fluent API.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Task>()
.HasMany<ApplicationUser>(s => s.Users)
.WithMany(c => c.Tasks)
.Map(cs =>
{
cs.MapLeftKey("TaskRefId");
cs.MapRightKey("ApplicationUserRefId");
cs.ToTable("TaskApplicationUser");
});
}
Update : you can see this link too.
EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType
Error text is not related to your many-to-many relationship. It tips that other built-in entities are not configured properly. So, It would be nice if you provided full definition of your custom DbContext-class and how it is configured.
UPDATE
As i understood u are working with two different contexts. You must work with the same context, cause of u are extending IdentityContext, creating relationships and adding custom types. So problem then will be resolved itself.
Hope, this will help.

entity framework code first not creating tables using VS 2012

I have a MVC4 Web api project under visual studio 2012 for which I would like to create and manage database using EF 6.0.2 code first. Actually, the solution entails four projects, namely,
OnlineShop.Application (User interface)
OnlineShop.Model dedicated to POCO classes only
OnlineShop.Test for unit tests and
OnlineShop.Core having UnitOfWork, GenericRepository and
DatabaseContext classes
Each of the mentioned projects includes an app.config which holds Same connection as that of web.config.
Problem: After running the project (in debug mode), the database is created as it's shown on server explorer (in visual studio 2012). But, it has no tables!!!
The database context class is also as the following:
public class DatabaseContext : DbContext
{
public DatabaseContext() : base("OnlineShopDb")
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<DatabaseContext, Configuration>());
}
//public static void InitializeDatabase()
//{
// using (var context = new DatabaseContext())
// {
// context.Database.CreateIfNotExists();
// Database.SetInitializer(new MigrateDatabaseToLatestVersion<DatabaseContext, Configuration>());
// }
//}
public DbSet<Person> Persons { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<Audit> Audits { get; set; }
public DbSet<RoleGroup> RoleGroups { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<UserInRole> UserInRoles { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<OrderDetail> OrderDetails { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<ProductCategory> ProductCategories { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Entity<Person>().Map<User>(c => c.Requires("Discriminator").HasValue("User"));
}
}
I have surfed the web so much, found lots of articles ans samples regarding EF code first approach but unfortunately couldn't handle this bad problem!
I would appreciate it if anyone could help me on this.
Entity Framework code first does not create your database until you try to access it, so run your project and try to get or insert some record to your database.
another usefull tip is that if you change your models EF by default will throw an exeption, and you will have to drop the current database so EF can crate a new one.
or I recomend you to change that default behavior this way

Code First doing strange migration when I add an interface to my entities

I have a strange problem with code first:
In project my entities looks like that and code first was doing migrations fine.
public class MyEntity
{
public Guid Id { get; set; }
public string Name { get; set; }
}
I decided to add an interface to my project like this one
public interface IEntity
{
Guid Id { get; set; }
bool IsDeleted { get; set; }
}
My new class now looks like that:
public class MyEntity : IEntity
{
public Guid Id { get; set; }
public string Name { get; set; }
bool IsDeleted { get; set; }
}
Now, if I try a migration with Code First, instead of adding a column here is what is doing code first:
DropForeignKey
DropIndex
Tries to CreateTable MyEntity table and breaks telling me this table already exists
Any idea why code first tries to do that?
Using EF5 I couldn't get it to repro. In general with migrations the order in which commands are executed is important so as the metadata is consistent between the database and models.
The correct order for these operations would be to either:
a) Run Enable-Migrations, Add-Migration then Update-Database before populating the database (i.e. running the app) then Add-Migration and Update database after each model change before running the app
b) run the app, Enable-Migrations, change the model, Add-Migrations, Update-Database, again making sure to run update the database after each model change is made
also note I am using a very simple DbContext that looks as such:
public class EntityContext : DbContext
{
public DbSet<MyEntity> MyEntities { get; set; }
}

Can Entity Framework 4 deal with two different data sources?

First, a little bit of context
I have one desktop application which uses a Paradox database and I am developing a new ASP.NET application using SQL Server to replace the current desktop app.
The transition will happen in tho phases. The first version of the web app will use SQL Server and Paradox at the same time. Legacy entities data will come from Paradox and data from new entities will come from SQL Server. So the desktop and web versions of the app can be used interchangeably.
In the second phase all data from Paradox will be imported to SQL Server. The old desktop app (and the Paradox db) won't be used anymore.
Now, the technical question
Imagine a simple model with two entities:
public class Customer
{
public Int32 ID { get; set; }
public String Name { get; set; }
virtual public IList<User> MyUsers { get; set; }
}
public class User
{
public Int32 ID { get; set; }
public String Name { get; set; }
virtual public Customer MyCustomer { get; set; }
}
public class SqlServerContext : DbContext
{
public SqlServerContext()
{
base.Configuration.ValidateOnSaveEnabled = false;
base.Configuration.LazyLoadingEnabled = true;
base.Configuration.ProxyCreationEnabled = true;
base.Configuration.AutoDetectChangesEnabled = true;
}
public DbSet<User> Users { get; set; }
public DbSet<Customer> Customers { get; set; }
}
When I use only SQL Server for both entities everything works fine. But now I want to retrieve customer data from Paradox and user data from SQL Server.
I then create a repository for the customers, with an underlying OleDbConnection using the Paradox provider. Of course, Entity Framework still creates the Customers table in SQL Server, since User has a Customer property.
I then removed the database relationship (FK) between User and Customer. Now I am able to insert a User related to a Customer, even though they're in different databases.
The problem is: when I try to retrieve a user from db [eg: context.Users.Find(id)] I can read the user's ID and Name, but user.Customer is null. I expected to get the customer ID through the user.Customer.ID property, since this data is in the Users table in SQL Server.
Am I going to the right path? If so, how can EF bring the customer ID for the user?
And if not, what would be a good approach for this scenario? I don't want to expose foreign key properties in the model (i.e: i don't want to have a int CustomerId property in the User entity).
Thanks in advance!
When you access user.MyCustomer, EF will issue a select statement to the Customers table and then materialize a Customer object. But in your case the table is empty or non existent.
What you can do is include a scalar property CustomerID on User class
public class User
{
public Int32 ID { get; set; }
public String Name { get; set; }
public int? CustomerID { get; set; }//assuming the db column name is also CustomerID
virtual public Customer MyCustomer { get; set; }
}
Then map the relationship as follows
public class SqlServerContext : DbContext
{
public SqlServerContext()
{
base.Configuration.ValidateOnSaveEnabled = false;
base.Configuration.LazyLoadingEnabled = true;
base.Configuration.ProxyCreationEnabled = true;
base.Configuration.AutoDetectChangesEnabled = true;
}
public DbSet<User> Users { get; set; }
public DbSet<Customer> Customers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasOptional(u => u.User)
.WithMany(c => c.MyUsers)
.HasForeignKey(u => u.CustomerID);
}
}
Then you can access the customer ID property using user.CustomerID instead of user.Customer.ID.