简体   繁体   中英

Cannot cast 'Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1[Microsoft.AspNetCore.Identity.IdentityUser`1[System.Int32]]'

PROBLEM:

System.InvalidCastException: 'Unable to cast object of type 'Microsoft.EntityFrameworkCore.Internal.InternalDbSet 1[Microsoft.AspNetCore.Identity.IdentityUser 1[System.Int32]]' to type 'System.Linq.IQueryable`1[DAL.User]'.'

RELEVANT CODE:

...
public class SocialNetworkDbContext : IdentityDbContext<IdentityUser<int>, IdentityRole<int>, int> 
...
public IQueryable<User> FindAll()
        {
            var allUsers = (IQueryable<User>)_socialNetworkDbContext.Users;
            if (allUsers == null)
            {
                throw new NoRecordFoundException();
            }
            return allUsers;

TRIED:

  1. public class SocialNetworkDbContext: IdentityDbContext<User>, IdentityRole<int>, int>

//no exception but this code breaks

            var result = await _userManager.CreateAsync(user, model.Password);
            await _userManager.AddToRoleAsync(user, model.Role);
  1. public IQueryable FindAll() { var allUsers = (IQueryable)_socialNetworkDbContext.Users.AsQueryable(); if (allUsers == null) { throw new NoRecordFoundException(); } return allUsers;

//the same exception

3)

public IQueryable<User> FindAll()
        {
            var allUsers = (IQueryable<User>)(IEnumerable<User>)_socialNetworkDbContext.Users;
            if (allUsers == null)
            {
                throw new NoRecordFoundException();
            }
            return allUsers;

// the same exception (unable to cast to IEnumerable). Cast to ICollection (unable to cast to ICollection)

Would be very thankful for any advice!!!

You should change your DbContext to use the actual user type:

public class SocialNetworkDbContext : IdentityDbContext<User, IdentityRole<int>, int>
{
}

If you have a class for the roles, you should use that as the generic type argument as well. This way you won't need any type casts.

From your code, it seems that the _socialNetworkDbContext.Users was stored the IdentityUser, instead of User model, right? So, after query data from the Users table, you could use the following code to convert the query result:

    public IQueryable<User> FindAll()
    { 
        var allUsers = _socialNetworkDbContext.Users.Select(c => new User()
        {
            UserName = c.UserName,
            Email = c.Email,
            //... other properties
        }).AsQueryable();
        if (allUsers == null)
        {
            throw new NoRecordFoundException();
        }
        return allUsers;
    }

Update

You can refer the following sample code:

Add an ApplicationUser class to customize the Identity User model:

public class ApplicationUser : IdentityUser<int>
{ 
    public string CustomTag { get; set; }
}

Use the ApplicationUser type as a generic argument for the context:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser, IdentityRole<int>, int>
{
    public DbSet<ApplicationUser> ApplicationUsers { get; set; }
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }
}

Update Pages/Shared/_LoginPartial.cshtml and replace IdentityUser with ApplicationUser:

@using Microsoft.AspNetCore.Identity
@using WebApp1.Areas.Identity.Data
@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager

Update the Startup.ConfigureServices and replace IdentityUser with ApplicationUser :

public void ConfigureServices(IServiceCollection services)
{ 
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));
    services.AddDatabaseDeveloperPageExceptionFilter();

    services.AddIdentity<ApplicationUser, IdentityRole<int>>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultUI()
            .AddDefaultTokenProviders();

    services.AddControllersWithViews();
}

Then, enable migration and generate the database.

After creating new user, the AspNetUser table data as below:

在此处输入图像描述

Create a UserViewModel and add the required properties:

public class UserViewModel
{
    public int UserId { get; set; }
    public string UserName { get; set; }
    public string Tag { get; set; }
}

Then, in the Controller, use the following code to query the user table:

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly ApplicationDbContext _context;
    public HomeController(ILogger<HomeController> logger, ApplicationDbContext context)
    {
        _logger = logger;
        _context = context;
    }

    public IActionResult Index()
    {
        var result = FindAll();
        return View();
    }
    public IQueryable<UserViewModel> FindAll()
    {
        var allUsers = _context.Users.Select(c => new UserViewModel()
        {
            UserId = c.Id,
            UserName = c.UserName,
            Tag = c.CustomTag
        });
        //if (allUsers == null)
        //{
        //    throw new NoRecordFoundException();
        //}
        return allUsers;
    }

The result as below:

在此处输入图像描述

try First(); or FirstOrDefault();

change your code:

    public async Task<List<User>> GetAllUsers()
        {
            var allUsers =  await _socialNetworkDbContext.Users.ToListAsync();
            if (allUsers == null)
            {
                throw new NoRecordFoundException();
            }
            return allUsers;
         }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM