使用 Entity Framework 的 IdentityRole 导航属性异常

IdentityRole Navigational Property Exception Using Entity Framework

我在将 "IdentityRole" 属性映射到我的 ApplicationUsers class 时遇到问题。我收到一个错误,结果是:

++++

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.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 class 看起来像这样

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;
        }
    }

我添加 and/or 查询的导航属性有什么问题。我真正想做的是 return 用户及其角色存储在我的数据库中。

谢谢!

首先应该是:

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

不是List<IdentityRole>

其次,通过从 Roles 属性 中的 IdentityUser 继承,此关系已存在于 ApplicationUser 上。您在此处创建了身份框架永远不会使用的次要关系。

此外,如果您希望您的 AspNetUserSites 遵循身份 table 的 table 名称方案,那么您只需指定 Table class 上的属性。以这种方式命名您的 class 是迟钝的。例如:

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

那么你就有了一个不错的 class 就像 Site 而不是 AspNetUserSite

更新

IdentityUserRole 只是 IdentityUserIdentityRole 之间的连接 table。在默认实现中,它的存在并没有太多意义,但您可以潜在地扩展 Identity classes 以通过这种方式附加有关关系的附加信息。

无论如何,如果您只想获得实际的 IdentityRoles,只需执行以下操作:

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