16

How does one change the PK column of the AspNetUser table from a guid to int data type? This should now be possible with the latest asp.net-identity version which got released today.

But I can't find anywhere how this is done?

Rob
  • 14,746
  • 28
  • 47
  • 65
Quoter
  • 4,236
  • 13
  • 47
  • 69

3 Answers3

17

By default the ASP.NET Identity (using Entity Framework) uses strings as the primary keys, not GUIDs, but it does store GUIDs in those string.

You need to define a few more classes, I've just created a new project (I'm using the VS2013 Update 2 CTP), here are the identity models you need to change:

public class ApplicationUser : IdentityUser<int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(ApplicationUserManager 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 class ApplicationUserRole : IdentityUserRole<int>
{
}

public class ApplicationUserLogin : IdentityUserLogin<int>
{
}

public class ApplicationUserClaim : IdentityUserClaim<int>
{
}

public class ApplicationRole : IdentityRole<int, ApplicationUserRole>
{
}

public class ApplicatonUserStore :
    UserStore<ApplicationUser, ApplicationRole, int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
    public ApplicatonUserStore(ApplicationDbContext context)
        : base(context)
    {
    }
}

public class ApplicationDbContext
    : IdentityDbContext<ApplicationUser, ApplicationRole, int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
    public ApplicationDbContext()
        : base("DefaultConnection")
    {
    }
}

You'll also need to update a few other places, just follow the compile errors, the most common change will be the need to convert the string returned form User.Identity.GetUserId() to an integer.

Also, In answering another question (I did ask the question though), I've provided an example solution that does just this, see the repository below:

https://github.com/JSkimming/AspNet.Identity.EntityFramework.Multitenant

Community
  • 1
  • 1
James Skimming
  • 4,991
  • 4
  • 26
  • 32
  • I see.. Is this still needed in the latest version of `asp.net-identity` that got released yesterday? I mean this much of custom code for just having the `int` as PK. – Quoter Mar 21 '14 at 18:28
  • 1
    Hi @Quoter . Yes, as far as I know, I did this using the latest release. The reason the default **string** implementation only has one entity model `ApplicationUser` class is because it derives from the non generic `IdentityUser` which itself derives from the generic `IdentityUser<>` class specifying a **string** `TKey` generic parameter. It's the same for the `ApplicationDbContext` class. Have a look at the classes using object browser, the [MSDN documentation](http://msdn.microsoft.com/en-us/library/microsoft.aspnet.identity.entityframework.aspx) has yet to be updated. – James Skimming Mar 21 '14 at 20:19
  • By the way, it took me about 10 minutes to make the necessary changes (granted I have done it before), because everything is strongly typed using generics, it's just a matter of following the compile errors. – James Skimming Mar 21 '14 at 20:25
  • How did you manage to fix the compiler error generated by `ChallengeResult()` which expects 3 strings. And the last one expects `User.Identity.GetUserId()` but I'm parsing that to an `int`. Same goes for `AuthenticationManager.GetExternalLoginInfoAsync()`. By the way, you'll find these methods in `AccountController()`. – Quoter Mar 21 '14 at 23:09
  • @JamesSkimming I also look at the post on http://www.asp.net/identity/overview/extensibility/change-primary-key-for-users-in-aspnet-identity but not sure if I have to add custom classes to IdentityModels as mentioned at step "Add customized Identity classes that use the key type" on that page. Because I am creating the project now and currently there is no table created. I mean that can I modify the current classes instead of adding the custom ones? – Jack Jul 31 '16 at 20:41
  • @binary unless ASP.NET Identity changed since I last used it (it's been a while) you need to define the classes if you want PK/FKs other than strings. – James Skimming Aug 02 '16 at 13:23
5

if anyone finds this while looking for identity 3.0 guide:

public class ApplicationUser : IdentityUser<int>
{
}

public class ApplicationRole : IdentityRole<int>
{
}

public class ApplicationDbContext: 
    IdentityDbContext<ApplicationUser, ApplicationRole, int>
{
}

in Startup.cs file, ConfigureServices method:

services.AddIdentity<ApplicationUser, ApplicationRole>()
    .AddEntityFrameworkStores<ApplicationDbContext, int>()//, int being the only difference
    .AddDefaultTokenProviders();

and that's all to it, no need to create your managers like in 2.0

found this in this blog post.

Travis Pessetto
  • 3,260
  • 4
  • 27
  • 55
pajics
  • 2,938
  • 3
  • 23
  • 27
2

have a look at this answer by hao-kung in this post

So if you want int ids, you need to create your own POCO IUser class and implement your IUserStore for your custom IUser class in the 1.0 RTM release.

This is something we didn't have time to support, but I'm looking into making this easy(ier) in 1.1 right now. Hopefully something will be available in the nightly builds soon.

Updated with 1.1-alpha1 example: How to get nightly builts

If you update to the latest nightly bits, you can try out the new 1.1-alpha1 apis which should make this easier now: Here's what plugging in Guids instead of strings should look like for example

public class GuidRole : IdentityRole<Guid, GuidUserRole> { 
    public GuidRole() {
        Id = Guid.NewGuid();
    }
    public GuidRole(string name) : this() { Name = name; }
}
public class GuidUserRole : IdentityUserRole<Guid> { }
public class GuidUserClaim : IdentityUserClaim<Guid> { }
public class GuidUserLogin : IdentityUserLogin<Guid> { }

public class GuidUser : IdentityUser<Guid, GuidUserLogin, GuidUserRole, GuidUserClaim> {
    public GuidUser() {
        Id = Guid.NewGuid();
    }
    public GuidUser(string name) : this() { UserName = name; }
}

private class GuidUserContext : IdentityDbContext<GuidUser, GuidRole, Guid, GuidUserLogin, GuidUserRole, GuidUserClaim> { }
private class GuidUserStore : UserStore<GuidUser, GuidRole, Guid, GuidUserLogin, GuidUserRole, GuidUserClaim> {
    public GuidUserStore(DbContext context)
        : base(context) {
    }
}
private class GuidRoleStore : RoleStore<GuidRole, Guid, GuidUserRole> {
    public GuidRoleStore(DbContext context)
        : base(context) {
    }
}

[TestMethod]
public async Task CustomUserGuidKeyTest() {
    var manager = new UserManager<GuidUser, Guid>(new GuidUserStore(new GuidUserContext()));
    GuidUser[] users = {
        new GuidUser() { UserName = "test" },
        new GuidUser() { UserName = "test1" }, 
        new GuidUser() { UserName = "test2" },
        new GuidUser() { UserName = "test3" }
        };
    foreach (var user in users) {
        UnitTestHelper.IsSuccess(await manager.CreateAsync(user));
    }
    foreach (var user in users) {
        var u = await manager.FindByIdAsync(user.Id);
        Assert.IsNotNull(u);
        Assert.AreEqual(u.UserName, user.UserName);
    }
}
Community
  • 1
  • 1
Nilesh Gajare
  • 6,302
  • 3
  • 42
  • 73
  • I don't get it, how does this change it from guids to int's? I don't see the datatype `int` here at all. What am I missing? – Quoter Mar 21 '14 at 09:34
  • 2
    @Quoter Let me first explain that the default implementation is using strings, not Guids, as you've pointed out in your question. Although they have the "guid format", they're actually being stored as strings. This example above shows you how to use real Guid types instead of strings, as an example of how to change to another data type. Changing to int should follow the same rules. – Nelson Reis Jul 08 '14 at 09:28
  • 1
    Reading your post after a few months, it makes sense. +2 – Quoter Aug 19 '14 at 18:43