0

When I try to log in to my development site, I get a weird error:

Invalid column name 'Email1'.

I've made derived classes for a number of different ASP.NET Identity 2.0 classes, namely:

public class MyUser : IdentityUser<int, MyLogin, MyUserRole, MyClaim>//, IUser<int>
{
    #region properties

    public string ActivationToken { get; set; }

    public string PasswordAnswer { get; set; }

    public string PasswordQuestion { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string TaxID { get; set; }

    public bool IsActive { get; set; }

    public bool IsApproved { get; set; }

    #endregion

    #region methods

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<MyUser, int> userManager)
    {
        var userIdentity = await userManager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        return userIdentity;
    }

    #endregion
}

The offending code is in the call to UserManager.FindAsync() in the Login method of the AccountController:

public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (ModelState.IsValid)
        {
            var user = await UserManager.FindAsync(model.Email, model.Password);
            if (user != null)
            {
                await SignInAsync(user, model.RememberMe);
                return RedirectToLocal(returnUrl);
            }
            ModelState.AddModelError("", "Invalid username or password.");
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

I've designed my User table as such:

CREATE TABLE [dbo].[User]
(
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Password] [nvarchar](50) NOT NULL,
    [FirstName] [nvarchar](50) NULL,
    [LastName] [nvarchar](50) NULL,
    [Email] [nvarchar](50) NOT NULL,
    [TaxID] [nvarchar](50) NULL,
    [PaymentMethodID] [int] NULL,
    [IsActive] [bit] NOT NULL DEFAULT 1,
    [IsApproved] [bit] NOT NULL,
    [IsLocked] [bit] NOT NULL,
    [CreationDate] [datetime] NULL,
    [ApprovalDate] [datetime] NULL DEFAULT NULL,
    [LastLoginDate] [datetime] NULL,
    [PasswordQuestion] [nvarchar](max) NULL,
    [PasswordAnswer] [nvarchar](max) NULL,
    [ActivationToken] [nvarchar](200) NULL,
    [EmailConfirmed] [bit] NOT NULL,
    [SecurityStamp] [nvarchar](max) NULL,
    [PhoneNumber] [nvarchar](50) NULL,
    [PhoneNumberConfirmed] [bit] NOT NULL,
    [TwoFactorEnabled] [bit] NOT NULL,
    [LockoutEndDateUtc] [datetime2](7) NULL,
    [LockoutEnabled] [bit] NOT NULL,
    [AccessFailedCount] [int] NOT NULL,
    CONSTRAINT [User_PK] PRIMARY KEY NONCLUSTERED ([ID]),
    CONSTRAINT [Email_UK] UNIQUE NONCLUSTERED([Email])
)

And I'm binding my MyUser class to that table in the OnModelCreating method of MyDbContext:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            // Map Entities to their tables.
            modelBuilder.Entity<MyUser>().ToTable("User");
            modelBuilder.Entity<MyRole>().ToTable("Role");
            modelBuilder.Entity<MyClaim>().ToTable("UserClaim");
            modelBuilder.Entity<MyLogin>().ToTable("UserLogin");
            modelBuilder.Entity<MyUserRole>().ToTable("UserRole");
            // Set AutoIncrement-Properties
            modelBuilder.Entity<MyUser>().Property(r => r.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            modelBuilder.Entity<MyClaim>().Property(r => r.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            modelBuilder.Entity<MyRole>().Property(r => r.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            // Override some column mappings that do not match our default
            modelBuilder.Entity<MyUser>().Property(r => r.UserName).HasColumnName("Email");
            modelBuilder.Entity<MyUser>().Property(r => r.PasswordHash).HasColumnName("Password");
        }

Somewhere Identity 2.0 is creating another Email column that it shouldn't. Any thoughts?

sshirley
  • 239
  • 2
  • 6
  • 19

1 Answers1

1

There's already a column with name Email in the default schema.

As @enki.dev suggest in his deleted answer if you look at the definition for IdentityUser you have those properties already defined.

You're doing something quite dangerous here:

modelBuilder.Entity<MyUser>().Property(r => r.UserName).HasColumnName("Email");
modelBuilder.Entity<MyUser>().Property(r => r.PasswordHash).HasColumnName("Password");

as you're trying to force one column into another. The property Email has been used extensively in this framework for password retrieval etc etc.

You can try and rename it

modelBuilder.Entity<MyUser>().Property(r => r.Email).HasColumnName("Blah");

so you wouldn't have the duplicate; but I guess you're going to face many other problems on the way.

Why don't you simply store the email in the UserName property ?

Another suggestion; it's always better to let the framework create the tables for you using the migration so you always know what's happening.

From Visual Studio choose menu

  • TOOLS - NuGet Packager Manager - Package Manager Console

select your project in the combo: Default Project.

Run Enable-Migrations.

It should create a folder called Migrations with a file called Configuration.cs.

The constructor should look like this:

public Configuration()
{
    AutomaticMigrationsEnabled = false;
}

change the value AutomaticMigrationsEnabled to true.

go back to Package Manager Console and run

Update-Database

or

Update-Database -Force

to recreate the whole schema for you tables.

There's a protected method there where you can see your data:

protected override void Seed(ASPNETIdentity2.Models.MyContext context)
{
    //  This method will be called after migrating to the latest version.

    //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
    //  to avoid creating duplicate seed data. E.g.
    //
    //    context.People.AddOrUpdate(
    //      p => p.FullName,
    //      new Person { FullName = "Andrew Peters" },
    //      new Person { FullName = "Brice Lambson" },
    //      new Person { FullName = "Rowan Miller" }
    //    );
    //
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
LeftyX
  • 35,328
  • 21
  • 132
  • 193
  • Thanks, wasn't positive that was the issue so I deleted it to go test things on my machine and never came back. Good to know. – matt. Jul 10 '15 at 16:49
  • Thanks Lefty for your answer. I am not using EF Code-First and migrations but rather Database First. In fact, I've already defined a lot of my database in a SQL Server Database Project. I'd say at this point that it would be hard to switch that all to Code First. So that being said, so when you said that I should store the email in the UserName column, you mean in the database itself? Which means I could get rid of the line: `code`modelBuilder.Entity().Property(r => r.UserName).HasColumnName("Email"); all together. – sshirley Jul 11 '15 at 19:20
  • @sshirley: yes, that's what I am suggesting. Save your email in the useraname field and email field. you can get rid of that line and things should work properly. – LeftyX Jul 12 '15 at 12:27
  • @leftyx could you please look at my question http://stackoverflow.com/questions/36929767/asp-net-identity-entity-framework-database-first-approach-with-own-table-definti – SivaRajini May 02 '16 at 10:04