EntityFrameworkCore throws NullReferenceException when querying data

0

I'm using EF Core 2.2 to connect to an Oracle11g database (using these old versions is a must), when I try to query one of my tables it throws a NullReferenceException in the EF Core external code. The Query:

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();

The exception:

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

The generated query:

[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

The query works as expected in Oracle SQL Developer. It seems that EF Core has some trouble converting the results to the entity (which in this case, the result should be none because the table has no data.) but I can not debug its code. (Or can I?)
The entity is configured in 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();
});

I can create and query other tables. Only AppUser table doesn't work in Oracle, it works fine using the SQL Server provider. Tell me if more info about anything is needed.


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

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

The configuration of 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");
});

I just noticed a text is written in my output just before the exception:

fail: Microsoft.EntityFrameworkCore.Query[10100]
      An exception occurred while iterating over the results of a query for context type 'Base.Security.Data.SecurityDbContext'.
oracle
asp.net-core
oracle11g
entity-framework-core
asked on Stack Overflow Feb 16, 2021 by Bamdad • edited Feb 17, 2021 by Bamdad

1 Answer

0

You have included UserRoleOrganizations twice . Try to do including the good old way:

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

But I don't like UserRoleOrganizations.Organization . Could you please show your User and UserRoleOrganizations clases?

Update.

Since I can see the classes, I think you can try to reverse query, maybe just for testing:


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;

And try to change the 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; }
....
}
   

answered on Stack Overflow Feb 16, 2021 by Serge • edited Feb 17, 2021 by Serge

User contributions licensed under CC BY-SA 3.0