4

I'm trying to add a Required property for ApplicationUser (ASP.NET Identity, MVC5)

Here's a simple example:

public class ApplicationUser : IdentityUser
{
    [Required]
    public string FirstName { get; set; }
}

The field is created in the database, but ends up NULLABLE
I expect the field to be NOT NULL.

enter image description here

Any idea how to get around this?

Kevin Radcliffe
  • 991
  • 1
  • 11
  • 21
  • It's hard to tell from just that. So you have the field defined on a form, and that form is submitted? Are you sending the data as AJAX, or standard postback? Are all the fields blank or just that one? – Brian Mains Nov 06 '13 at 17:11
  • Thanks. I'm not dealing with the front-end side (that's all fine). I need the database to create a NOT NULL field. That is expected when using [Required] – Kevin Radcliffe Nov 06 '13 at 17:16
  • 1
    This is a great example and I expect that a lot of people are trying to do a similar thing. It *should* be possible to only store the extended ApplicationUser entities and not store separate IdentityUser entities at all. – Derek Tomes Nov 07 '13 at 19:22
  • I have a similar issue -- trying to add a bool property to ApplicationUser, but I don't care if it is nullable or not. When I add the property and run update-database, I get the error: "The 'ShowCompleted' property on 'ApplicationUser' could not be set to a 'null' value. You must set this property to a non-null value of type 'System.Boolean'." – Number8 Nov 19 '13 at 15:58
  • @Number8 seems weird, since that's almost the opposite of what we ran into. Have you tried explicitly making it a nullable bool? (i.e. bool? ShowCompleted) – Kevin Radcliffe Nov 20 '13 at 20:05
  • @KR -- yes, I did make it a nullable bool, and it seems to work as expected now. Not sure what else I might have done, though... – Number8 Nov 20 '13 at 22:07

5 Answers5

8

Table per Hierarchy (TPH) mapping is the default in Entity Framework Code First. This means that if FirstName isn't required in all the classes in the type hierarchy that share the same table, then the column cannot be non-null.

If you want the FirstName column to be non-nullable you could choose a different mapping strategy. If you use Table per Type (TPT) instead, then you will have one table for the IdentityUser (AspNetUsers by default) and another for ApplicationUser. As the FirstName now is unique to the ApplicationUser table it can be non-nullable.

To use TPT you can override the OnModelCreating method like this:

protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
    modelBuilder.Entity<ApplicationUser>().ToTable("ApplicationUser");
}
Olav Nybø
  • 11,454
  • 8
  • 42
  • 34
  • 4
    Yeah, that's what I had to do. This seems really counterintuitive, especially since extending the ApplicationUser is a core piece of ASP.NET Identity, you'd think there would be some official way around this. – Kevin Radcliffe Nov 06 '13 at 21:00
  • 1
    When I tried to do this, I get this error when running "update-database -force": "Foreign key 'FK_dbo.ApplicationUser_dbo.AspNetUsers_Id' references invalid table 'dbo.AspNetUsers'." – Number8 Nov 19 '13 at 16:01
  • 1
    How do I prevent the creation of the parent user table that represents IdentityUser? – Ronen Festinger Feb 19 '14 at 11:50
0

I tried to add a non nullable string field in the IdentityUser using the Required attribute as well as overriding the OnModelCreating method as below:

protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<ApplicationUser>().Property(x => x.FirstName).IsRequired();

    base.OnModelCreating(modelBuilder);
}

No success on both. I don't know if this is by design, or a bug in the new ASP.NET Identity. I also searched for bug related but no success.

Maybe adding a migration would help you achieve what you need for now.

gsimoes
  • 1,011
  • 11
  • 12
0

Found a method to do this by combining the answers here and here

The final solution is really counterintuitive to me.
It seems that you need to explicitly have a separate table name for ApplicationUser.
Also, you must make sure that base.OnModelCreating(modelBuilder) is called first
If you don't do it this way, the field will never honor the NOT NULL aspect of the [Required] attribute.

Here is the code I used which finally got this working:

public class ApplicationUser : IdentityUser
{
    public string FirstName { get; set; }
}

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        //modelBuilder.Entity<IdentityUser>().ToTable("Users"); // Won't work if the table name is the same.
        modelBuilder.Entity<ApplicationUser>().ToTable("Users")
            .Property(p => p.FirstName).IsRequired();
    }
    // etc.
}

Which results in the following DB structure:

enter image description here

Community
  • 1
  • 1
Kevin Radcliffe
  • 991
  • 1
  • 11
  • 21
  • 1
    I don't really like this solution, personally, as it splits the Users table up. Will leave this question open for awhile to see if there is a more intuitive answer. – Kevin Radcliffe Nov 06 '13 at 20:58
  • Your last solution didn't work for me. SQL statements generated that caused error. As you see AspNetUsers is renamed and FK is being added. – user2596613 Mar 01 '14 at 21:53
0

I was able to make such a field not null by adding the following line to the seed method in the configuration.cs file

context.Database.ExecuteSqlCommand("ALTER TABLE [AspNetUsers] ALTER COLUMN [FirstName] nvarchar(MAX) NOT NULL");

Luxfer
  • 21
  • 2
0

This is more of a comment to @Number8 above (not allowed to comment at this time). I ran into same issue, which is probably relevant to the OP's issue. Database-Update checks the migration's Configuration class (Configuration.cs). If you have a seed method, you need to set default values for non-null properties in your seed method (or make them nullable in the model).

AKhooli
  • 1,285
  • 1
  • 13
  • 11