繁体   English   中英

EntityFrameworkCore 查询数据时抛出 NullReferenceException

[英]EntityFrameworkCore throws NullReferenceException when querying data

我正在使用 EF Core 2.2 连接到 Oracle11g 数据库(必须使用这些旧版本),当我尝试查询我的一个表时,它会在 EF Core 外部代码中引发NullReferenceException 查询:

string username = "Administrator";
var user = _context.Users.Where(x => x.UserName.ToUpper() == username.ToUpper())
                    .Include(x => x.UserProfile)
                    .Include(x => x.UserRoleOrganizations).ThenInclude(s => s.Role)
                    .Include(x => x.UserRoleOrganizations).ThenInclude(s => s.Organization);

return user.FirstOrDefault();

例外:

System.NullReferenceException
  HResult=0x80004003
  Message=Object reference not set to an instance of an object.
  Source=Microsoft.EntityFrameworkCore.Relational
  StackTrace:
   at Microsoft.EntityFrameworkCore.Storage.TypedRelationalValueBufferFactoryFactory.CreateGetValueExpression(Expression dataReaderExpression, Int32 index, TypeMaterializationInfo materializationInfo, Boolean detailedErrorsEnabled, Boolean box)
   at Microsoft.EntityFrameworkCore.Storage.TypedRelationalValueBufferFactoryFactory.<>c__DisplayClass13_0.<CreateArrayInitializer>b__0(TypeMaterializationInfo mi, Int32 i)
   at System.Linq.Enumerable.<SelectIterator>d__5`2.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Dynamic.Utils.CollectionExtensions.ToReadOnly[T](IEnumerable`1 enumerable)
   at System.Linq.Expressions.Expression.NewArrayInit(Type type, IEnumerable`1 initializers)
   at Microsoft.EntityFrameworkCore.Storage.TypedRelationalValueBufferFactoryFactory.CreateArrayInitializer(CacheKey cacheKey, Boolean detailedErrorsEnabled)
   at Microsoft.EntityFrameworkCore.Storage.TypedRelationalValueBufferFactoryFactory.<Create>b__11_0(CacheKey k)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.EntityFrameworkCore.Internal.NonCapturingLazyInitializer.EnsureInitialized[TParam,TValue](TValue& target, TParam param, Func`2 valueFactory)
   at Microsoft.EntityFrameworkCore.Query.Internal.ShaperCommandContext.NotifyReaderCreated(DbDataReader dataReader)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.BufferlessMoveNext(DbContext _, Boolean buffer)
   at Oracle.EntityFrameworkCore.Storage.Internal.OracleExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.MoveNext()
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ResultEnumerable`1.GetEnumerator()
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.<_TrackEntities>d__17`2.MoveNext()
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext()
   at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass15_1`1.<CompileQueryCore>b__0(QueryContext qc)
   at Base.Security.Business.UserManagement.GetUser(String username) in C:\Users\Afagh2\source\repos\HSE2_Oracle\Base.Security\Business\UserManagement.cs:line 88

生成的查询:

[Parameters=[:ToUpper_0='ADMINISTRATOR' (Size = 256)], CommandType='Text', CommandTimeout='0']
Select
K0 "Id", K1 "AccessFailedCount", K2 "ConcurrencyStamp", K3 "Email", K4 "EmailConfirmed", K5 "FirstName", K6 "IsActive", K7 "IsExternal", K8 "LastName", K9 "LockoutEnabled", K10 "LockoutEnd", K11 "NationalCode", K12 "NormalizedEmail", K13 "NormalizedUserName", K14 "OrganizationName", K15 "OrganizationType", K16 "PasswordHash", K17 "PersonnelCode", K18 "PhoneNumber", K19 "PhoneNumberConfirmed", K20 "PositionName", K21 "SecurityStamp", K22 "TwoFactorEnabled", K23 "UserName", K24 "Id", K25 "FileContent", K26 "FileExtension", K27 "FileName" from(
  SELECT "x"."Id" K0, "x"."AccessFailedCount" K1, "x"."ConcurrencyStamp" K2, "x"."Email" K3, "x"."EmailConfirmed" K4, "x"."FirstName" K5, "x"."IsActive" K6, "x"."IsExternal" K7, "x"."LastName" K8, "x"."LockoutEnabled" K9, "x"."LockoutEnd" K10, "x"."NationalCode" K11, "x"."NormalizedEmail" K12, "x"."NormalizedUserName" K13, "x"."OrganizationName" K14, "x"."OrganizationType" K15, "x"."PasswordHash" K16, "x"."PersonnelCode" K17, "x"."PhoneNumber" K18, "x"."PhoneNumberConfirmed" K19, "x"."PositionName" K20, "x"."SecurityStamp" K21, "x"."TwoFactorEnabled" K22, "x"."UserName" K23, "x.UserProfile"."Id" K24, "x.UserProfile"."FileContent" K25, "x.UserProfile"."FileExtension" K26, "x.UserProfile"."FileName" K27
  FROM "AppUser" "x"
  LEFT JOIN "AppUserProfilePicture" "x.UserProfile" ON ("x"."Id" = "x.UserProfile"."Id")
  WHERE ("UPPER"("x"."UserName") = :ToUpper_0)
  ORDER BY "x"."Id"
) "m1"
where rownum <= 1

该查询在 Oracle SQL Developer 中按预期工作。 似乎 EF Core 在将结果转换为实体时遇到了一些麻烦(在这种情况下,结果应该是 none,因为表没有数据。)但我无法调试它的代码。 (或者我可以吗?)
实体在OnModelCreating中配置:

builder.Entity<ApplicationUser>(b =>
{
    b.HasKey(u => u.Id);
    b.HasIndex(u => u.NormalizedUserName).HasName("UserNameIndex").IsUnique();
    b.HasIndex(u => u.NormalizedEmail).HasName("EmailIndex");
    b.ToTable("AppUser");
    b.Property(u => u.ConcurrencyStamp).IsConcurrencyToken();

    b.Property(u => u.UserName).HasMaxLength(256);
    b.Property(u => u.NormalizedUserName).HasMaxLength(256);
    b.Property(u => u.Email).HasMaxLength(256);
    b.Property(u => u.NormalizedEmail).HasMaxLength(256);

    b.HasOne(x => x.UserProfile).WithOne(x => x.User).HasForeignKey<ApplicationUserProfilePicture>(x => x.Id);
    b.HasMany<IdentityUserClaim<int>>().WithOne().HasForeignKey(uc => uc.UserId).IsRequired();
    b.HasMany<IdentityUserLogin<int>>().WithOne().HasForeignKey(ul => ul.UserId).IsRequired();
    b.HasMany<IdentityUserToken<int>>().WithOne().HasForeignKey(ut => ut.UserId).IsRequired();
    b.HasMany<ApplicationUserRoleOrganization>().WithOne().HasForeignKey(ur => ur.UserId).IsRequired();
});

我可以创建和查询其他表。 只有AppUser表在 Oracle 中不起作用,使用 SQL 服务器提供程序可以正常工作。 告诉我是否需要有关任何内容的更多信息。


更新
用户 class:

public class ApplicationUser : Microsoft.AspNetCore.Identity.IdentityUser<int>
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    [StringLength(450)]
    public string PositionName { get; set; }
    [StringLength(450)]
    public string NationalCode { get; set; }
    [StringLength(450)]
    public string PersonnelCode { get; set; }
    public bool IsActive { get; set; } = true;
    public bool IsExternal { get; set; } = false;
    [Required]
    public OrganizationTypeEnum OrganizationType { get; set; }
    public string OrganizationName { get; set; }
    public virtual ApplicationUserProfilePicture UserProfile { get; set; }
    public virtual ICollection<ApplicationUserRoleOrganization> UserRoleOrganizations { get; set; }
}

用户角色组织 class:

public class ApplicationUserRoleOrganization : Microsoft.AspNetCore.Identity.IdentityUserRole<int>
{
    public int Id { get; set; }
    public override int RoleId { get => base.RoleId; set => base.RoleId = value; }
    public override int UserId { get => base.UserId; set => base.UserId = value; }
    public virtual int OrganizationId { get; set; }
    public virtual ApplicationUser User { get; set; }
    public virtual ApplicationRole Role { get; set; }
    public virtual Organization Organization { get; set; }
}

UserRoleOrganization 的配置:

builder.Entity<ApplicationUserRoleOrganization>(b =>
{
    b.HasKey(r => r.Id);
    b.HasIndex(t => t.OrganizationId).HasName("OrganizationIndex");
    b.HasIndex(t => t.RoleId).HasName("RoleIndex");
    b.HasIndex(t => t.UserId).HasName("UserIndex");
    b.HasOne(userRole => userRole.Role)
    .WithMany(role => role.UserRoleOrganizations)
    .HasForeignKey(userRole => userRole.RoleId).HasConstraintName("FK_RoleOrg_Role_RoleId");
    b.HasOne(userRole => userRole.Organization)
    .WithMany(role => role.UserRoleOrganizations)
    .HasForeignKey(userRole => userRole.OrganizationId).HasConstraintName("FK_RoleOrg_Org_OrgId");
    b.HasOne(userRole => userRole.User)
    .WithMany(user => user.UserRoleOrganizations)
    .HasForeignKey(userRole => userRole.UserId).HasConstraintName("FK_RoleOrg_User_UserId");
    b.ToTable("AppUserRoleOrganization");
});

我刚刚注意到在异常之前在我的 output 中写了一条文本:

fail: Microsoft.EntityFrameworkCore.Query[10100]
      An exception occurred while iterating over the results of a query for context type 'Base.Security.Data.SecurityDbContext'.

您已包含 UserRoleOrganizations 两次。 尝试做包括好的旧方法:

string username = "Administrator";
return _context.Users.Where(x => x.UserName.ToUpper() == username.ToUpper())
                    .Include(x => x.UserProfile)
                    .Include("UserRoleOrganizations.Organization");
                    .Include("UserRoleOrganizations.Role")
                    .FirstOrDefault();

但我不喜欢 UserRoleOrganizations.Organization。 您能否展示您的 User 和 UserRoleOrganizations 类?

更新。

由于我可以看到这些类,我认为您可以尝试反向查询,也许只是为了测试:


var userRoleOrganizations=_context.UserRoleOrganizations
.Where(x => x.User.UserName.ToUpper() == username.ToUpper())
.Include(s => s.Role)
.Include(s => s.Organization)
.ToList();

var user = _context.Users
.Where(x => x.UserName.ToUpper() == username.ToUpper())
.Include(x => x.UserProfile)
.FirstOrDefault();

user.UserRoleOrganizations=userRoleOrganizations;

return user;

并尝试更改 UserRoleOrganizations class:

public class UserRoleOrganizations
{
....
public  override int? RoleId { get => base.RoleId; set => base.RoleId = value; }
 public override int? UserId { get => base.UserId; set => base.UserId = value; }
 public virtual int? OrganizationId { get; set; }
....
}
   

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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