2015-01-07 3 views
0

У меня возникла проблема, отображающая свойство IdentityRole для моего класса ApplicationUsers. Я получаю сообщение об ошибке с эффектом:Исключение навигационной собственности IdentityRole с использованием инфраструктуры Entity Framework

++++

The declared type of navigation property WebApp.Core.DAL.ApplicationUsers.IdentityRoles is not  compatible with the result of the specified navigation. 

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.Data.Entity.Core.MetadataException: The declared type of navigation property WebApp.Core.DAL.ApplicationUsers.IdentityRoles is not compatible with the result of the specified navigation. 

Source Error: 


Line 28:    using (CMSContext cntx = new CMSContext()) 
Line 29:    { 
Line 30:     var users = cntx.Users 
Line 31:         .Include(m => m.IdentityRoles) 
Line 32:         .Include(s => s.AspNetUsersSites) 

Source File: c:\LocalSites\WebApp\1.0.0.0\DAL\UserManagement\User.cs Line: 30 

Stack Trace: 


[MetadataException: The declared type of navigation property  WebApp.Core.DAL.ApplicationUsers.IdentityRoles is not compatible with the result of the specified navigation. ] 
    System.Data.Entity.Core.Query.PlanCompiler.PreProcessor.ValidateNavPropertyOp(PropertyOp op) +401 
    System.Data.Entity.Core.Query.PlanCompiler.PreProcessor.Visit(PropertyOp op, Node n) +80 
    System.Data.Entity.Core.Query.PlanCompiler.SubqueryTrackingVisitor.VisitChildren(Node n) +163 
    System.Data.Entity.Core.Query.PlanCompiler.PreProcessor.VisitScalarOpDefault(ScalarOp op, Node n) +33 
    System.Data.Entity.Core.Query.PlanCompiler.SubqueryTrackingVisitor.VisitChildren(Node n) +163 
    System.Data.Entity.Core.Query.InternalTrees.BasicOpVisitorOfNode.VisitDefault(Node n) +22 
    System.Data.Entity.Core.Query.InternalTrees.BasicOpVisitorOfNode.VisitAncillaryOpDefault(AncillaryOp op, Node n) +21 
    System.Data.Entity.Core.Query.PlanCompiler.SubqueryTrackingVisitor.VisitChildren(Node n) +163 
    System.Data.Entity.Core.Query.InternalTrees.BasicOpVisitorOfNode.VisitDefault(Node n) +22 
      System.Data.Entity.Core.Query.InternalTrees.BasicOpVisitorOfNode.VisitAncillaryOpDefault(AncillaryOp op, Node n) +21 
    System.Data.Entity.Core.Query.PlanCompiler.SubqueryTrackingVisitor.VisitChildren(Node n) +163 
    System.Data.Entity.Core.Query.PlanCompiler.SubqueryTrackingVisitor.VisitRelOpDefault(RelOp op, Node n) +38 
    System.Data.Entity.Core.Query.PlanCompiler.PreProcessor.Visit(ProjectOp op, Node n) +599 
    System.Data.Entity.Core.Query.PlanCompiler.SubqueryTrackingVisitor.VisitChildren(Node n) +163 
    System.Data.Entity.Core.Query.InternalTrees.BasicOpVisitorOfNode.VisitDefault(Node n) +22 
     System.Data.Entity.Core.Query.InternalTrees.BasicOpVisitorOfNode.VisitPhysicalOpDefault(PhysicalOp op, Node n) +21 
    System.Data.Entity.Core.Query.PlanCompiler.PreProcessor.Process(Dictionary`2& tvfResultKeys) +106 
    System.Data.Entity.Core.Query.PlanCompiler.PreProcessor.Process(PlanCompiler planCompilerState, StructuredTypeInfo& typeInfo, Dictionary`2& tvfResultKeys) +54 
    System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Compile(List`1& providerCommands, ColumnMap& resultColumnMap, Int32& columnCount, Set`1& entitySets) +236 
    System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition..ctor(DbProviderFactory storeProviderFactory, DbCommandTree commandTree, DbInterceptionContext interceptionContext, IDbDependencyResolver resolver, BridgeDataReaderFactory bridgeDataReaderFactory, ColumnMapFactory columnMapFactory) +441 

++++

У меня есть отложенная загрузка и выключение моего класс ApplicationUsers выглядит следующим образом

namespace WebApp.Core.Contracts 
{ 
    public class ApplicationUsers : IdentityUser 
    { 
    public bool IsActive { get; set; } 
    public string LockoutReason { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string Photo { get; set; } 

    public virtual List<AspNetUsersSites> AspNetUsersSites { get; set; } 

    // a collection of roles that can be written to, since it needs to be evaluated earlier before it's disposed of 
    [ForeignKey("Id")] 
    public virtual List<IdentityRole> IdentityRoles { get; set; } 

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUsers> 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 async Task<IList<string>> GenerateUserRolesAsync(UserManager<ApplicationUsers> manager, string userId) 
    { 
     var userRoles = await manager.GetRolesAsync(this.Id); 
     return userRoles; 
    } 

    public async Task DeleteUser(UserManager<ApplicationUsers> manager, string username) 
    { 
     var user = manager.FindByName(username);    
     await manager.DeleteAsync(user); 
    }     
} 

Мой запрос Linq выглядит следующим образом

public static List<Contracts.ApplicationUsers> GetUsersForSiteWithRoles(int SiteID){ 
     using (CMSContext cntx = new CMSContext()) 
     { 
      var users = cntx.Users 
          .Include(m => m.IdentityRoles) 
          .Include(s => s.AspNetUsersSites) 
          .Where(i => i.AspNetUsersSites.Where(s => s.SiteID == SiteID).Count() > 0).ToList(); 

      return users; 
     } 
    } 

Что не так с навигационным свойством, которое я добавил, и/или с запросом. Все, что я действительно пытаюсь сделать, это вернуть пользователям свои роли, которые хранятся в моей базе данных.

Спасибо!

ответ

1

Во-первых, он должен быть:

public virtual ICollection<IdentityRole> IdentityRoles { get; set; } 

Не List<IdentityRole>.

Во-вторых, эта связь уже существует на ApplicationUser через наследование от IdentityUser в Roles. Здесь вы создаете вторичные отношения, которые никогда не будут использоваться инфраструктурой Identity.

Кроме того, если вы хотите, чтобы ваш AspNetUserSites соответствовал схеме имен таблиц таблиц Identity, вам нужно указать только атрибут Table в классе. Именование вашего класса таким образом является тупым. Например:

[Table("AspNetUserSites")] 
public class Site 
{ 
    ... 
} 

Тогда вы просто иметь хороший класс как Site вместо AspNetUserSite

UPDATE

IdentityUserRole только объединение таблицы между IdentityUser и IdentityRole. В реализации по умолчанию не существует много смысла в его существовании, но вы можете расширить классы Identity, чтобы приложить дополнительную информацию о взаимоотношениях таким образом.

В любом случае, если вы просто хотите получить при фактической IdentityRoles, просто сделать что-то вроде:

var roleIds = user.Roles.Select(r => r.RoleId).ToList(); 
var roleNames = db.Roles.Where(r => roleIds.Contains(r.Id)).Select(r => r.Name); 
+0

Спасибо за объяснение Криса. Я определенно новичок в ASP.NET Identity и структуре сущности в целом. Я рассмотрел это, и я вижу, что экземпляр ApplicationUser имеет свойство «.Roles». Но это свойство содержит коллекцию «IdentityUserRole». И все это, кажется, содержит идентификатор роли, а не имя роли. Есть ли способ получить коллекцию ролей, которая имеет как ролик, так и имя? – Solo812

+0

По существу, я пытаюсь выполнить экземпляр пользователя, а затем прокрутить их IdentityRoles и выписать имя роли на экран. Мне кажется (на основе моего ограниченного понимания), что я не могу получить доступ к имени роли через экземпляр пользователя. Это верно? – Solo812

+0

См. Обновление выше. –

Смежные вопросы