Jak mogę zmienić nazwy tabel podczas korzystania z tożsamości ASP.NET?

213

Używam wersji (RTM, a nie RC) Visual Studio 2013 (pobranej z MSDN 2013-10-18), a zatem najnowszej (RTM) wersji AspNet.Identity. Kiedy tworzę nowy projekt internetowy, wybieram „Indywidualne konta użytkowników” do uwierzytelnienia. Spowoduje to utworzenie następujących tabel:

  1. AspNetRoles
  2. AspNetUserClaims
  3. AspNetUserLogins
  4. AspNetUserRoles
  5. AspNetUsers

Kiedy rejestruję nowego użytkownika (przy użyciu domyślnego szablonu), te tabele (wymienione powyżej) są tworzone, a tabela AspNetUsers ma wstawiony rekord, który zawiera:

  1. ID
  2. Nazwa Użytkownika
  3. PasswordHash
  4. SecurityStamp
  5. Dyskryminator

Dodatkowo, dodając właściwości publiczne do klasy „ApplicationUser” z powodzeniem dodałem dodatkowe pola do tabeli AspNetUsers, takie jak „FirstName”, „LastName”, „PhoneNumber” itp.

Oto moje pytanie. Czy istnieje sposób na zmianę nazw powyższych tabel (gdy są tworzone po raz pierwszy), czy zawsze będą one nazywać AspNetprzedrostkiem, jak wymieniłem powyżej? Jeśli nazwy tabel można nazwać inaczej, wyjaśnij, w jaki sposób.

-- AKTUALIZACJA --

Wdrożyłem rozwiązanie @Hao Kung. Tworzy nową tabelę (na przykład nazwałem ją MyUsers), ale nadal tworzy tabelę AspNetUsers. Celem jest zastąpienie tabeli „AspNetUsers” tabelą „MyUsers”. Zobacz kod poniżej i obraz bazy danych utworzonych tabel.

W rzeczywistości chciałbym zastąpić każdą AspNettabelę własną nazwą ... Na przykład MyRoles, MyUserClaims, MyUserLogins, MyUserRoles i MyUsers.

Jak to osiągnąć i skończyć z jednym zestawem tabel?

public class ApplicationUser : IdentityUser
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string PostalCode { get; set; }
    public string PhonePrimary { get; set; }
    public string PhoneSecondary { get; set; }
}

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext(): base("DefaultConnection")
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<IdentityUser>().ToTable("MyUsers");
    }
}

Tabele bazy danych

- ODPOWIEDŹ NA AKTUALIZACJĘ -

Dzięki zarówno Hao Kungowi, jak i Peterowi Stulinskiemu. To rozwiązało mój problem ...

    protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<IdentityUser>().ToTable("MyUsers").Property(p => p.Id).HasColumnName("UserId");
        modelBuilder.Entity<ApplicationUser>().ToTable("MyUsers").Property(p => p.Id).HasColumnName("UserId");
        modelBuilder.Entity<IdentityUserRole>().ToTable("MyUserRoles");
        modelBuilder.Entity<IdentityUserLogin>().ToTable("MyUserLogins");
        modelBuilder.Entity<IdentityUserClaim>().ToTable("MyUserClaims");
        modelBuilder.Entity<IdentityRole>().ToTable("MyRoles");
    }
użytkownik2315985
źródło
Jesteś pewny? Usuń wszystkie tabele, usuń tabelę _migracji, a następnie spróbuj. Kod, który opublikowałem poniżej, który jest bardzo podobny do twojego, nie tworzy tabeli AspNetUsers.
Piotr Stulinski
1
Jedyną różnicą między twoim kodem a moim jest to, że zmieniłem nazwę ApplicationUser na „User”. Moje zachowanie jest zupełnie inne. Przy pierwszym tworzeniu tworzy tabele zgodnie z potrzebami i podanymi nazwami. Może tylko dla „eksperymentu” spróbuj zmienić ApplicationUser na User, a następnie dodaj linie base.OnModelCreating (modelBuilder); modelBuilder.Entity <IdentityUser> () .ToTable („Użytkownicy”, „dbo”); modelBuilder.Entity <ApplicationUser> () .ToTable („Użytkownicy”, „dbo”);
Piotr Stulinski
1
Zaktualizowano rozwiązanie powyżej ...
user2315985,
6
@Daskul Usuń modelBuilder.Entity <IdentityUser> () .ToTable („MyUsers”). Właściwość (p => p.Id) .HasColumnName („UserId”); w takim przypadku kolumna dyskryminatora nie zostanie dodana do tabeli MyUsers. Zobacz ten błąd, aby uzyskać więcej informacji: stackoverflow.com/questions/22054168/…
Sergey
1
@ user2315985 - Powinieneś zaktualizować swoją odpowiedź, aby usunąć wiersz zawierający, modelBuilder.Entity<IdentityUser>().ToTable("MyUsers").Property(p => p.Id).HasColumnName("UserId");jak wspomniano przez @Sergey. W przeciwnym razie nowo nazwana MyUserstabela ma kolumnę dyskryminującą, jak wskazał @Daskul. Również MyUserClaimsstruktura tabeli będzie niepoprawna, jak wskazał @Matt Ogólnie. Myślę, że pomysł, aby dodać, że pochodzi z komentarza do @Giang na blogu msdn , ale jest zły!
kimbaudi

Odpowiedzi:

125

Możesz to zrobić łatwo, modyfikując plik IdentityModel.cs zgodnie z poniższym opisem:

Zastąp OnModelCreating w swoim DbContext, a następnie dodaj następujące elementy, zmieni to tabelę AspNetUser na „Użytkownicy”. Możesz także zmienić nazwy pól, domyślna kolumna Id stanie się User_Id.

modelBuilder.Entity<IdentityUser>()
                    .ToTable("Users", "dbo").Property(p => p.Id).HasColumnName("User_Id");

lub po prostu poniżej, jeśli chcesz zachować wszystkie standardowe nazwy kolumn:

modelBuilder.Entity<IdentityUser>()
                        .ToTable("Users", "dbo")

Pełny przykład poniżej (powinien znajdować się w pliku IdentityModel.cs) zmieniłem klasę ApplicationUser na User.

public class User : IdentityUser
    {
        public string PasswordOld { get; set; }
        public DateTime DateCreated { get; set; }

        public bool Activated { get; set; }

        public bool UserRole { get; set; }

    }

public class ApplicationDbContext : IdentityDbContext<User>
    {
        public ApplicationDbContext()
            : base("DefaultConnection")
        {
        }

        protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<IdentityUser>()
                .ToTable("Users", "dbo").Property(p => p.Id).HasColumnName("User_Id");
            modelBuilder.Entity<User>()
                .ToTable("Users", "dbo").Property(p => p.Id).HasColumnName("User_Id");
        }
    }

Uwaga: nie udało mi się uruchomić tej funkcji, jeśli istnieje bieżąca tabela. Zwróć także uwagę, że kolumny, których nie zamapujesz, zostaną utworzone domyślne.

Mam nadzieję, że to pomaga.

Piotr Stulinski
źródło
2
Aby te zmiany weszły w życie, należy użyć migracji do wypchnięcia zmian do istniejącej bazy danych.
Łukasz
2
Jeśli to zrobisz, twoje klucze obce będą trochę dziwne, nie sądzę, że musisz zmienić nazwę tabeli w IdentityUser. Zobacz ten post SO
Matt
Tak samo jak dodatkowa kontrola, jak wcześniej mnie złapała. Upewnij się, że wywołanie base.OnModelCreatingto pierwszy wiersz kodu w przesłonięciu, w przeciwnym razie pozostałe wiersze zostaną zastąpione przez podstawową klasę tożsamości.
DavidG
@DavidG Dziękuję rzeczywiście
SA
Dobre rozwiązanie. Ale nie trzeba zastępować nazwy tabeli dla IdentityUser. Zobacz to rozwiązanie stackoverflow.com/questions/28016684/…
EJW 11.04.17
59

Poniżej znajduje się moje działające rozwiązanie:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder); // This needs to go before the other rules!

        modelBuilder.Entity<ApplicationUser>().ToTable("User");
        modelBuilder.Entity<IdentityRole>().ToTable("Role");
        modelBuilder.Entity<IdentityUserRole>().ToTable("UserRole");
        modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaim");
        modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogin");
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }
}

Zobacz to po więcej szczegółów

Frank Myat Thu
źródło
Czy możesz to zrobić, określając atrybuty zamiast (brzydkiego) płynnego interfejsu API?
Mariusz Jamro
Dokonałem drobnej zmiany, ponieważ jakoś udało mi się zanegować tę odpowiedź i nie zauważyłem! Zaktualizowałem go również, aby używał preferowanej metody dla takich linków[text](link)
DavidG,
Utworzyłem pusty projekt MVC, uruchomiłem go 1 raz i utworzono tabele o nazwach asp. Następnie dodałem tę drobną zmianę, usunąłem wszystkie moje tabele i folder migracji (na ile warto) i ponownie uruchomiłem mój kod, ale nazwy tabel odmówiły zmiany. Następnie stworzyłem zupełnie nowy projekt, dokonałem tej zmiany przed uruchomieniem, a teraz działa. Czy brakuje mi czegoś bardzo oczywistego?
mathkid91,
15

Możesz spróbować zastąpić tę metodę w klasie DbContext, aby zamapować ją na wybraną tabelę:

    protected override void OnModelCreating(DbModelBuilder modelBuilder) {
        modelBuilder.Entity<IdentityUser>()
            .ToTable("AspNetUsers");
Hao Kung
źródło
7
Nie zapomnij zadzwonić, base.OnModelCreating(modelBuilder);bo reszta modelu nie zostanie utworzona.
Ferruccio
Zaktualizowałem moje pytanie po wdrożeniu rozwiązania @Hao Kung, ale problem nadal występuje, zobacz moje edytowane pytanie powyżej. Dzięki.
user2315985,
1

Możesz także utworzyć klasy konfiguracji i określić każdy szczegół każdej ze swoich klas tożsamości, na przykład:

using System.Data.Entity.ModelConfiguration;

public class ApplicationUserConfig : EntityTypeConfiguration<ApplicationUser>
{
    public UserConfig()
    {
        ToTable("Users");
        Property(u => u.LocationName).IsRequired();
    }
}

A następnie włącz te konfiguracje do metody OnModelCreating ():

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Configurations.Add(new ApplicationUserConfig());
        ...
    }

To da ci pełną kontrolę nad każdym aspektem klas tożsamości.

Manish
źródło
1

Tylko w celu dokumentacji, dla tego, który przychodzi do tego postu na temat lat, które się pojawią w przyszłości (jak ja XD), Wszystkie odpowiedzi rezygnujące z mojego komentarza są prawidłowe, ale możesz po prostu zastosować tę metodę podaną przez Alexandru Bucur na jego blogu

         //But this method is not longer supported on netcore > 2.2, so I need to fix it
         foreach (var entityType in modelBuilder.Model.GetEntityTypes())
         {
            var table = entityType.Relational().TableName;
             if (table.StartsWith("AspNet"))
             {
                 entityType.Relational().TableName = table.Substring(6);
             }
         };

        //This is the functional way on NetCore > 2.2
        foreach (var entityType in modelBuilder.Model.GetEntityTypes())
        {
            var tableName = entityType.GetTableName();
            if (tableName.StartsWith("AspNet"))
            {
                entityType.SetTableName(tableName.Substring(6));
            }
        }
sgrysoft
źródło
0

Możemy zmienić domyślne nazwy tabel asp.net Identity w następujący sposób:

    public class ApplicationDbContext : IdentityDbContext
    {    
        public ApplicationDbContext(): base("DefaultConnection")
        {
        }

        protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<IdentityUser>().ToTable("user");
            modelBuilder.Entity<ApplicationUser>().ToTable("user");

            modelBuilder.Entity<IdentityRole>().ToTable("role");
            modelBuilder.Entity<IdentityUserRole>().ToTable("userrole");
            modelBuilder.Entity<IdentityUserClaim>().ToTable("userclaim");
            modelBuilder.Entity<IdentityUserLogin>().ToTable("userlogin");
        }
    }

Ponadto możemy rozszerzyć każdą klasę i dodać dowolną właściwość do klas takich jak „IdentityUser”, „IdentityRole”, ...

    public class ApplicationRole : IdentityRole<string, ApplicationUserRole>
{
    public ApplicationRole() 
    {
        this.Id = Guid.NewGuid().ToString();
    }

    public ApplicationRole(string name)
        : this()
    {
        this.Name = name;
    }

    // Add any custom Role properties/code here
}


// Must be expressed in terms of our custom types:
public class ApplicationDbContext 
    : IdentityDbContext<ApplicationUser, ApplicationRole, 
    string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
    public ApplicationDbContext()
        : base("DefaultConnection")
    {
    }

    static ApplicationDbContext()
    {
        Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

    // Add additional items here as needed
}

Aby zaoszczędzić czas, możemy użyć rozszerzalnego szablonu projektu AspNet Identity 2.0, aby rozszerzyć wszystkie klasy.

Arvand
źródło
0

Ale to nie działa w .NET CORE (MVC 6), dlatego musimy zmienić powiązanie na

lubić

protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);

    builder.Entity<IdentityRole>().ToTable("Role");
    builder.Entity<IdentityUser>(entity => 
    {
        entity.ToTable("User");
        entity.Property(p => p.Id).HasColumnName("UserId");
    });
}

Może komuś pomóc :)

dnxit
źródło
czy działa to zarówno dla kodu najpierw, jak i bazy danych?
liang
Najpierw nie próbowałem bazy danych, ale chyba powinna działać, jeśli model i baza danych są takie same.
dnxit