2016-10-11 4 views
1

Arbeiten mit Entity Framework-Code zuerst.EntityType '' IdentityUserRole 'hat keinen Schlüssel definierten Fehler

Der Versuch, die IdentityRole-ID als Fremdschlüssel für eine benutzerdefinierte Klasse zu verwenden.

Die Beziehung ist korrekt, aber wenn ich versuche, Daten zu meiner benutzerdefinierten Tabelle hinzuzufügen, erhalte ich diesen Fehler.

EntityType 'IdentityUserRole' hat keinen Schlüssel definiert. Definieren Sie den Schlüssel für diesen EntityType. IdentityUserRoles: EntityType: EntitySet 'IdentityUserRoles' basiert auf Typ 'IdentityUserRole', die keine Schlüssel definiert hat.

Code:

Benutzerdefinierte Tabelle/Klasse

public class UserRoleAccess 
{ 
    [Key] 
    public long UserRoleAccessId { get; set; } 

    public string UserRoleId { get; set; } 

    public virtual ApplicationRole ApplicationRole { get; set; } 

    public bool IsActive { get; set; } 

    public string Name { get; set; } 

    public int UserRoleAccessType { get; set; } 
} 

IdentityRole:

public class ApplicationRole : IdentityRole 
{ 
    public virtual ICollection<UserRoleAccess> UserRoleAccess { get; set; } 
} 

Bindungen:

protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder) 
    { 
     base.OnModelCreating(modelBuilder); 
     modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); 


     modelBuilder.Entity<IdentityUser>().ToTable("Users").Property(p => p.Id).HasColumnName("UserId"); 
     modelBuilder.Entity<ApplicationUser>().ToTable("Users").Property(p => p.Id).HasColumnName("UserId"); 
     modelBuilder.Entity<IdentityUserRole>().ToTable("UserRoles"); 
     modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogins"); 
     modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaims"); 
     modelBuilder.Entity<IdentityRole>().ToTable("Roles"); 
     modelBuilder.Entity<ApplicationRole>().ToTable("Roles"); 
     modelBuilder.Entity<UserRoleAccess>().ToTable("UserRoleAccess"); 

     modelBuilder.Entity<ApplicationUser>().HasRequired(p => p.Person) 
      .WithMany(b => b.Users); 

     modelBuilder.Entity<ApplicationUser>().HasRequired(p => p.Person) 
      .WithMany(b => b.Users) 
      .HasForeignKey(p => p.PersonId); 

     modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId); 
     modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id); 
     modelBuilder.Entity<ApplicationRole>().HasKey<string>(r => r.Id); 
     modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId }); 


    } 

Beziehung in db (richtig):

enter image description here

versucht, auf eine ID-Eigenschaft Erstellen und eine [Key] Attribut Einstellung, aber es hat nicht funktioniert:

public class ApplicationRole : IdentityRole 
{ 
    [Key] 
    public string Id { get; set; } 

    public virtual ICollection<UserRoleAccess> UserRoleAccess { get; set; } 
} 

Führen Sie diesen Code beim Hinzufügen Daten:

public static void CreateUserRoleAccess(string name, int type, string id) 
    { 

     using (var context = new UserRoleAccessContext()) 
     { 
      var userRoleAccess = new UserRoleAccess(); 

      userRoleAccess.ApplicationRole = new ApplicationRole { Id = id }; 

      userRoleAccess.UserRoleId = id; 
      userRoleAccess.IsActive = true; 

      userRoleAccess.UserRoleAccessType = type; 

      userRoleAccess.Name = name; 

      context.UserRoleAccess.Add(userRoleAccess); 

      context.SaveChanges(); 
     } 
    } 

Was vermisse ich?

EDIT:

IdentityRole Klasse:

IdentityRole

+0

wir kein neues Schlüsselwort vor Objecttype verwenden, tun, tun wir? öffentliche neue Zeichenfolge Id {get; einstellen; } – Waleed

+0

@Waled etwas Nachschärfer hinzugefügt. Wie hilft dein Kommentar? Mit oder ohne das neue Schlüsselwort vor der Eigenschaft Es funktioniert immer noch nicht – ThunD3eR

+0

Können Sie die IdentityRole-Klasse buchen? Sie haben eine Zuordnung zum IdentityRole-Schlüssel in Ihrem Modell Builder – matthijsb

Antwort

1

Also, Sie verwenden MVC 5 mit ASP.NET Identity 2.0. Ich nehme an, Ihr Projekt hat das Nuget-Paket für Microsoft.AspNet.Identity.EntityFramework und die richtigen Tabellen wurden in Ihrer Datenbank erstellt.

Vielleicht liegt Ihr Problem daran, dass Sie die Zuordnungen für die Standard-Identity-Tabellen neu definieren. Müssen Sie die Tabellennamen und Schlüssel wirklich explizit zuordnen? Ich würde versuchen, die ursprünglichen Zuordnungen beizubehalten und nur explizite Zuordnungen für Ihre benutzerdefinierten Entitäten und Felder hinzuzufügen. Ich denke, dass Sie die ToTable-Zuordnungen nicht benötigen, da die Basiseinheiten irgendwo im Code eine Zuordnung haben und Ihre Entitäten sie erweitern.

Ein paar Fragen:

  • Was ist die Bedeutung von UserRoleAccess.UserRoleId ist? Ist es eine Benutzer-ID oder eine Rollen-ID?Wenn die UserRole-ID enthalten sein soll, handelt es sich um einen zusammengesetzten Schlüssel und nicht um einen einzelnen Wert. Daher ist es nicht wahrscheinlich, dass eine String-Eigenschaft ausreichen würde. Vielleicht solltest du es umbenennen.

  • Was tun Sie genau in dem Verfahren zu tun, wollen CreateUserRoleAccess: das Hinzufügen eines neuen UserRoleAccess für eine Rolle und Benutzer, die bereits existieren und sind bereits im Zusammenhang (dh die UserRole Beziehung bereits vorhanden ist)? Oder fügen Sie entweder einen neuen UserRole und für einen Benutzer und eine Rolle hinzu, die bereits existieren, aber nicht verwandt sind? Ich nehme an, dass Sie die Rolle oder den Benutzer an diesem Punkt nicht erstellen möchten, sie existieren bereits, liege ich falsch?

  • Wie auch immer, in Ihrem CreateUserRoleAccess Verfahren, in dieser Zeile:

    userRoleAccess.ApplicationRole = new ApplicationRole { Id = id }; 
    

    Es sei denn, Sie eine neue Rolle in diesem selben Moment zu schaffen, sollten Sie eine Find oder andere Linq Abfrage tun und die vorhandene Rolle von der Get Kontext. Vielleicht nur dies zu ändern würde Ihr Code funktioniert:

    //userRoleAccess.ApplicationRole = new ApplicationRole { Id = id }; 
    userRoleAccess.ApplicationRole = context.Roles.Find(id) as ApplicationRole; 
    

habe ich ein MVC-Projekt und versucht, Ihren Code mit mehreren Änderungen:

Ich habe keine explizite EF-Bindungen oder Zuordnungen enthalten, nur um Versuchen Sie es mit dem ursprünglichen Identity-Modell und sehen Sie, ob es funktioniert.

I erweitert Identität DbContext nur DbSet für UserRoleAccess Zugabe:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser> 
{ 
    public virtual IDbSet<UserRoleAccess> UserRoleAccesses { get; set; } 

    public ApplicationDbContext() 
     : base("DefaultConnection", throwIfV1Schema: false) 
    { 
    } 

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

nach dem benutzerdefinierten Entitäten ApplicationRole und UserRoleAccess Hinzufügen einer Migration und Aktualisierung der Datenbank zu erzeugen ich, als Sie die gleiche UserRoleAccess Tisch bekam, sondern auch eine neue Spalte Diskriminatorfilter in der Tabelle Rollen:

enter image description here

das bedeutet, EF wird mit TPH (Tabelle pro Hierarchie), wenn Sie die IdentityRole verlängern Entität mit Ihrer ApplicationRole Einheit. Sie teilen den Tisch. Dies ist implizit, keine Notwendigkeit, Bindungen zu schreiben (in der Tat, unnötige explizite Bindungen neigen dazu, zu stören).

Also, wenn Ihre Rolle Tabelle dieses Feld fehlt, kann dies eine mögliche Ursache für Sie Fehler sein.

Ich lief das MVC-Web und erstellt einen neuen Benutzer mit dem Link Registrieren in der Kopfzeile der Seite. Ich betreibe den folgenden Code (durch zum Index-Controller hinzufügen), und es hat funktioniert:

public void CreateUserRoleAccess(string name, int type, string id) 
    { 
     //Insert role (run only once) 
     using (var context = new ApplicationDbContext()) 
     { 
      var role = new ApplicationRole { Id = id, Name = "Role1" }; 
      var user = context.Users.FirstOrDefault<ApplicationUser>(); 
      //user.Roles.Add(role); 
      role.Users.Add(new IdentityUserRole { RoleId = role.Id, UserId = user.Id }); 

      context.Roles.Add(role); 
      context.SaveChanges(); 
     } 

     using (var context = new ApplicationDbContext()) 
     { 
      var userRoleAccess = new UserRoleAccess(); 

      //userRoleAccess.ApplicationRole = new ApplicationRole { Id = id }; 
      userRoleAccess.ApplicationRole = context.Roles.Find(id) as ApplicationRole; 

      //Is this a userId or a roleId? Does not seem OK to assign id param here 
      userRoleAccess.UserRoleId = id; 
      userRoleAccess.IsActive = true; 

      userRoleAccess.UserRoleAccessType = type; 

      userRoleAccess.Name = name; 

      context.UserRoleAccesses.Add(userRoleAccess); 

      context.SaveChanges(); 
     } 
    } 

Bitte beachte, dass ich mit einem anderen Kontext Rahmen zunächst eine neue Rolle zu erstellen, um sicherzustellen, dass die Rolle liegt vor, wenn ich bekommen der interessante Code. Ich benutze diese Rolle, um sie später aus dem Kontext zu bekommen.

Hoffe, das hilft. Ich kann Ihnen den vollständigen Lösungscode senden, wenn Sie möchten.

EDIT - UserRoleAccess Tabelle:

UserRoleAccess table

 CreateTable(
      "dbo.UserRoleAccesses", 
      c => new 
       { 
        UserRoleAccessId = c.Long(nullable: false, identity: true), 
        UserRoleId = c.String(), 
        IsActive = c.Boolean(nullable: false), 
        Name = c.String(), 
        UserRoleAccessType = c.Int(nullable: false), 
        ApplicationRole_Id = c.String(maxLength: 128), 
       }) 
      .PrimaryKey(t => t.UserRoleAccessId) 
      .ForeignKey("dbo.AspNetRoles", t => t.ApplicationRole_Id) 
      .Index(t => t.ApplicationRole_Id); 

Nützliche Links:

Introduction to ASP.NET Identity - habe ich die einfache MVC-Lösung diese Informationen verwenden.

ASP.NET Identity, extract from book Pro ASP.NET MVC 5

+0

Für die Mühe abstimmen! Vielen Dank! Obwohl ich nicht sicher bin, dass Sie genau verstanden, was ich tun wollte. Können Sie ein Bild anzeigen, wie Ihre UserRoleAccess-Tabelle aussieht? Es scheint mir, dass Sie einen Forein-Schlüssel aus der AspNetUsers-Tabelle und der AspnetRole-Tabelle haben. Ich möchte nur ein Schlüsselattribut aus der Tabelle aspNetRoles haben. In der CreateUserRoleAccess-Methode gibt uns die ID eine ID einer bereits vorhandenen Rolle. Und ich werde versuchen Sie versuchen, indem Sie die ID finden, wie Sie vorgeschlagen. – ThunD3eR

+0

Gern geschehen! Ich habe die Tabelle UserRoleAccess zur Antwort hinzugefügt. Es gibt einen Fremdschlüssel aus der AspNetRoles-Tabelle und nicht aus der AspNetUsers-Tabelle. – Diana

+0

Also, was Sie wollen, ist die Eigenschaft UserRoleId als Fremdschlüsselfeld und ApplicationRole als Navigationseigenschaft? Sie können das mit dem ForeignKey-Attribut tun, wie folgt: '[ForeignKey (" UserRoleId ")] öffentliche virtuelle ApplicationRole ApplicationRole {get; einstellen; } '. Sie können das Attribut entweder in die ApplicationRole-Eigenschaft oder in die UserRoleId-Eigenschaft einfügen, nur der Parameter muss der andere Eigenschaftsname sein. – Diana

Verwandte Themen