Efcore: Query: Threading issues cause NullReferenceException in SimpleNullableDependentKeyValueFactory

Created on 21 May 2016  路  25Comments  路  Source: dotnet/efcore

I am getting random crash when getting the list but not sure why.

        [HttpGet]
        public async Task<List<BookingTimeSlotViewModel>> Get(DateTime start, DateTime end) // need period
        {
            User user = await GetCurrentUser();

            // get booking slots with booking detail
            IQueryable<BookingTimeSlot> slots;
            if (await IsAmbassadorManager()) {
                slots = _rosterRepository.GetBookingSlotForManagerBetween(user, start, end);
            } else {
                slots = _rosterRepository.GetBookingSlotForUserBetween(user, start, end);
            }

            return _mapper.Map<List<BookingTimeSlot>, List<BookingTimeSlotViewModel>>(await slots.ToListAsync()); // <<<<<<<<<< CRASH HERE
        }

// repository
        public IQueryable<BookingTimeSlot> GetBookingSlotForUserBetween(User user, DateTime start, DateTime end)
        {
            return GetBookingSlotBetween(start, end).Where(s => s.Booking.Outlet.Supervisor == user);
        }

        public IQueryable<BookingTimeSlot> GetBookingSlotBetween(DateTime start, DateTime end)
        {
            return _context.BookingTimeSlots
                .Include(s => s.Booking.Outlet)
                .Include(s => s.Rosters)
                .Where(s => s.StartDate <= end && (s.EndDate >= start || (s.Repeat == true && s.RepeatUntil >= start)));
        }

Here is the exception log:


---> (Inner Exception #0) System.AggregateException: One or more errors occurred. (One or more errors occurred. (Object reference not set to an instance of an object.)) ---> System.AggregateException: One or more errors occurred. (Object reference not set to an instance of an object.) ---> System.NullReferenceException: Object reference not set to an instance of an object.
at lambda_method(Closure , InternalEntityEntry )
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SimpleNullableDependentKeyValueFactory`1.TryCreateFromCurrentValues(InternalEntityEntry entry, TKey& key)
at Microsoft.EntityFrameworkCore.Query.Internal.WeakReferenceIdentityMap`1.CreateIncludeKeyComparer(INavigation navigation, InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.IncludeCore(Object entity, INavigation navigation)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.<IncludeAsync>d__13.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncGroupJoinInclude.<IncludeAsync>d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncGroupJoinInclude.<IncludeAsync>d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.EntityFrameworkCore.Query.AsyncQueryMethodProvider.GroupJoinAsyncEnumerable`4.GroupJoinAsyncEnumerator.<MoveNext>d__6.MoveNext()
--- End of inner exception stack trace ---
--- End of inner exception stack trace ---
---> (Inner Exception #0) System.AggregateException: One or more errors occurred. (Object reference not set to an instance of an object.) ---> System.NullReferenceException: Object reference not set to an instance of an object.
at lambda_method(Closure , InternalEntityEntry )
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SimpleNullableDependentKeyValueFactory`1.TryCreateFromCurrentValues(InternalEntityEntry entry, TKey& key)
at Microsoft.EntityFrameworkCore.Query.Internal.WeakReferenceIdentityMap`1.CreateIncludeKeyComparer(INavigation navigation, InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.IncludeCore(Object entity, INavigation navigation)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.<IncludeAsync>d__13.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncGroupJoinInclude.<IncludeAsync>d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncGroupJoinInclude.<IncludeAsync>d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.EntityFrameworkCore.Query.AsyncQueryMethodProvider.GroupJoinAsyncEnumerable`4.GroupJoinAsyncEnumerator.<MoveNext>d__6.MoveNext()
--- End of inner exception stack trace ---
---> (Inner Exception #0) System.NullReferenceException: Object reference not set to an instance of an object.
at lambda_method(Closure , InternalEntityEntry )
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SimpleNullableDependentKeyValueFactory`1.TryCreateFromCurrentValues(InternalEntityEntry entry, TKey& key)
at Microsoft.EntityFrameworkCore.Query.Internal.WeakReferenceIdentityMap`1.CreateIncludeKeyComparer(INavigation navigation, InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.IncludeCore(Object entity, INavigation navigation)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.<IncludeAsync>d__13.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncGroupJoinInclude.<IncludeAsync>d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncGroupJoinInclude.<IncludeAsync>d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.EntityFrameworkCore.Query.AsyncQueryMethodProvider.GroupJoinAsyncEnumerable`4.GroupJoinAsyncEnumerator.<MoveNext>d__6.MoveNext()<---
<---
<---
<---
<---
<---
closed-fixed type-bug

Most helpful comment

I have found what causes the error in my project and created a new project that replicates the issue.

The problem occurs when the model has a one-to-many object (Post) that has a navigation property to a 'parent' (Blog), but that 'many' object (Post) does not specify a property BlogId in the model (see comment in BloggingContext.cs in project).

This in itself does not cause an error but a query which includes context.Posts.Where(x=> x.Blog.Id == 3) causes the null reference exception with repeated requests (but a single request does work).

project with issue: https://github.com/hallzhallz/dotnetcore/tree/master/efcoretest
To replicate run the project go to /api/Test then click 'fetch' which will create 100 requests for /api/Values.

Let me know if anything needs clarification.

All 25 comments

@alexlau811 Can you post the code for DbContext and entities involved?

Also, when you say "random crash" do you mean that it sometimes crashes and sometimes doesn't when run with the exact same code against the exact same data? Or do you mean that it crashes with some data in the database, but not with other data in the database?

@ajcvickers

It crashes with exact same code and same data in the database randomly. Not sure if my code has any race condition while it only happens on this particular query and works well on other similar queries.

The code involved seems quite lengthy so not sure if you mind me putting a zip instead of pasting here. Please let me know if more codes are required.

Entities involved:

BaseEntity
BaseOutlet : BaseEntity
BookingTimeSlots : BaseEntity
Outlet : BaseOutlet
Roster : BaseEntity
User : BaseEntity
UserRole : BaseEntity

issue#5456.zip

@alexlau811 Are multiple threads calling into the context concurrently? The context is not thread safe and so using the same context instance from multiple threads can cause issues like this.

EF Team Triage: Closing this issue as the requested additional details have not been provided and we have been unable to reproduce it.

Hi,

I'm having the same error.
I think it has something to do with the JOINS it must create.

I'm using Entity Framework Core RC2.

at lambda_method(Closure , InternalEntityEntry )
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SimpleNullableDependentKeyValueFactory`1.TryCreateFromCurrentValues(InternalEntityEntry entry, TKey& key)
   at Microsoft.EntityFrameworkCore.Query.Internal.WeakReferenceIdentityMap`1.CreateIncludeKeyComparer(INavigation navigation, InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.IncludeCore(Object entity, INavigation navigation)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.Include(QueryContext queryContext, Object entity, IReadOnlyList`1 navigationPath, IReadOnlyList`1 relatedEntitiesLoaders, Int32 currentNavigationIndex, Boolean queryStateManager)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.Include(QueryContext queryContext, Object entity, IReadOnlyList`1 navigationPath, IReadOnlyList`1 relatedEntitiesLoaders, Boolean queryStateManager)
   at Microsoft.EntityFrameworkCore.Query.Internal.GroupJoinInclude.Include(Object entity)
   at Microsoft.EntityFrameworkCore.Query.QueryMethodProvider.<_GroupJoin>d__26`4.MoveNext()
   at System.Linq.Enumerable.<SelectManyIterator>d__22`3.MoveNext()
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()`

``` C#
public class Customer
{
public int ID { get; set; }
public string Name { get; set; }
public int? CityID { get; set; }
public virtual City City { get; set; }
}

public class City
{
public int ID { get; set; }
public string Name { get; set; }
public string PostalCode { get; set; }
public int? CountryID { get; set; }
public virtual Country Country { get; set; }
}

public class Country
{
public int ID { get; set; }
public string Name { get; set; }
}

public class Demo
{
public void Demo(DataContext db)
{
foreach (Customer customer in db.Customers.Where(l => l.Name == 'Jan Hop'))
{
// THIS WORKS
}

    foreach (Customer customer in db.Customers.Where(l => l.City.PostalCode == '2000'))
    {
        // THIS WORKS
    }

    foreach (Customer customer in db.Customers.Where(l => l.Name == 'Jan Hop').Include(l => l.City))
    {
        // THIS WORKS
    }

    foreach (Customer customer in db.Customers.Where(l => l.City.PostalCode == '2000').Include(l => l.City))
    {
        // THIS DOESN'T WORK
    }
}

}
```

Marking for re-triage. Could be a query bug.

Tried this simple repro in both RC2 and current builds and it didn't fail for me, so I guess it might be data dependent or require additional model configuration. @microef could you make necessary changes to make it fail:

``` C#
using Microsoft.EntityFrameworkCore;
using System.Linq;

namespace ConsoleApplication76
{
class Program
{
static void Main(string[] args)
{
using (var db = new MyContext())
{
db.Database.EnsureDeleted();
db.Database.EnsureCreated();

            db.Add(new Customer { Name = "Hop Jan" });
            db.Add(new Customer { Name = "Jan Hop", City = new City { PostalCode = "2000" } });
            db.SaveChanges();
        }
        using (var db = new MyContext())
        {
            foreach (Customer customer in db.Customers.Where(l => l.City.PostalCode == "2000").Include(l => l.City))
            {
                // THIS DOESN'T WORK
            }
        }
    }
}

public class Customer
{
    public int ID { get; set; }
    public string Name { get; set; }
    public int? CityID { get; set; }
    public virtual City City { get; set; }
}

public class City
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string PostalCode { get; set; }
    public int? CountryID { get; set; }
    public virtual Country Country { get; set; }
}

public class Country
{
    public int ID { get; set; }
    public string Name { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<Country> Countries { get; set; }
    public DbSet<City> Cities { get; set; }
    public DbSet<Customer> Customers { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Data Source=(localdb)\\mssqllocaldb;Initial Catalog=muuu;Integrated Security=true");
    }
}

}
```

Hi,

I had exact same error, using Entity Framework Core RC2. What I can add is that this issue is not data dependent: I've created Console Application that shared same Model and DbContext definition and configuration, and used same exact database than my MVC 6 web app which was crashing with one particular query (very similiar to this above). In console app, linq query worked, and in my web app it didn't, and this behavior was 100% reproducible every single time. There was not a single unnecessary method called besides the query in both apps when I was testing this. Very strange.

@tennlos Are you sure that the context is only being accessed by a single thread in the web app? Can you post your code, including what you have in Startup for the web app?

@ajcvickers Yes, I am pretty sure it is accessed only by a single thread, the Startup in the web app is exactly the same as in project template, but in case it is needed

``` C#
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

        if (env.IsDevelopment())
        {
            // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
            builder.AddUserSecrets();

            // This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
            builder.AddApplicationInsightsSettings(developerMode: true);
        }

        builder.AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddApplicationInsightsTelemetry(Configuration);

        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

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

        services.AddMvc();

        // Add application services.
        services.AddTransient<IEmailSender, AuthMessageSender>();
        services.AddTransient<ISmsSender, AuthMessageSender>();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseApplicationInsightsRequestTelemetry();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
            app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        app.UseApplicationInsightsExceptionTelemetry();

        app.UseStaticFiles();

        app.UseIdentity();

        // Add external authentication middleware below. To configure them please see http://go.microsoft.com/fwlink/?LinkID=532715

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

Controller:

``` C#
public async Task<IActionResult> Index(int teamId)
        {
            var user = await GetCurrentUserAsync();
            if (user != null)
            {
                //some stuff here, in the end this query is called:
                using (var context = new ApplicationDbContext(new DbContextOptions<ApplicationDbContext>()))
                {
                    var transfers = context.Transfer.Include(x => x.Team).ThenInclude(x => x.User);
                    //line below throws exception
                    var userTransfers = transfers.Where(x => x.Team.User.Id == userId).ToList();
                }
                return View(vmodel);         
            }

        }

@tennlos Can you post the code for your ApplicationDbContext and entity types. It is interesting that you are newing up a new context instance in the controller, rather than using the one from D.I. I am wondering how it gets its connection string--presumably you have some code in OnConfiguring? On the other hand, the GetCurrentUserAsync call is presumably getting the context instance from D.I. There is no reason this shouldn't all work, but it looks a little strange.

@ajcvickers
Actually, I use an existing context instance, but in this one case I tried to create new instance to see if this would fix my problem (it didn't).

ApplicationDbContext:

``` C#
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions options)
: base(options)
{
}

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.Entity<PlayerTransfers>(entity =>
        {
            entity.HasOne(d => d.PlayerIn)
                .WithMany(p => p.PlayerInTransfers)
                .HasForeignKey(d => d.PlayerInID).OnDelete(DeleteBehavior.Cascade);

            entity.HasOne(d => d.PlayerOut)
                .WithMany(p => p.PlayerOutTransfers)
                .HasForeignKey(d => d.PlayerOutID).OnDelete(DeleteBehavior.Restrict);

            entity.HasOne(d => d.Transfer)
                .WithMany(p => p.PlayerTransfers)
                .HasForeignKey(d => d.TransferID);

        });

        builder.Entity<TeamPlayer>(entity =>
        {
            entity.HasOne(d => d.Player)
                .WithMany(p => p.PlayerTeams)
                .HasForeignKey(d => d.PlayerID).OnDelete(DeleteBehavior.Cascade);

            entity.HasOne(d => d.Team)
                .WithMany(p => p.PlayerTeams)
                .HasForeignKey(d => d.TeamID).OnDelete(DeleteBehavior.Cascade);

        });

        builder.Entity<CompetitionPlayer>(entity =>
        {
            entity.HasOne(d => d.PlayerData)
                .WithMany(p => p.CompetitionPlayers)
                .HasForeignKey(d => d.PlayerDataID).OnDelete(DeleteBehavior.Cascade);

            entity.HasOne(d => d.Competition)
                .WithMany(p => p.CompetitionPlayers)
                .HasForeignKey(d => d.CompetitionID).OnDelete(DeleteBehavior.Cascade);

        });

        base.OnModelCreating(builder);
        // Customize the ASP.NET Identity model and override the defaults if needed.
        // For example, you can rename the ASP.NET Identity table names and more.
        // Add your customizations after calling base.OnModelCreating(builder);
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Data Source=(localdb)\\mssqllocaldb;Initial Catalog=aspnet-FantasyLeague-e6e1925f-ad46-4fa8-88cc-4552653bc628;Integrated Security=true");
    }

    public DbSet<Player> Player { get; set; }
    public DbSet<Team> Team { get; set; }
    public DbSet<Transfer> Transfer { get; set; }
    public DbSet<PlayerTransfers> PlayerTransfers { get; set; }
    public DbSet<TeamPlayer> TeamPlayer { get; set; }
    public DbSet<PlayerData> PlayerData { get; set; }
    public DbSet<Competition> Competition { get; set; }
    public DbSet<CompetitionPlayer> CompetitionPlayer { get; set; }
}

Some of my model entities involved in this query:

``` C#
    public class Transfer
    {
        public Transfer()
        {
            PlayerTransfers = new HashSet<PlayerTransfers>();
        }
        public int ID { get; set; }

        [Required]
        public Team Team { get; set; }
        public DateTime TransferDate { get; set; }
        public int GameWeek { get; set; }

        public virtual ICollection<PlayerTransfers> PlayerTransfers { get; set; }
    }

    public class PlayerTransfers
    {
        public int ID { get; set; }
        public int TransferID { get; set; }
        public int PlayerInID { get; set; }
        public int PlayerOutID { get; set; }

        public virtual Player PlayerOut { get; set; }
        public virtual Player PlayerIn { get; set; }
        public virtual Transfer Transfer { get; set; }
        public decimal PriceDifference { get; set; }
    }

    public class Team
    {
        public Team()
        {
            PlayerTeams = new HashSet<TeamPlayer>();
        }

        public int ID { get; set; }

        public ApplicationUser User { get; set; }
        public string Name { get; set; }
        public DateTime CreatedOn { get; set; }
        public int Season { get; set; }
        public virtual ICollection<TeamPlayer> PlayerTeams { get; set; }
    }

We have the similar problem. And we have web application project where we reproduced the bug. This exception is throwing when we are calling db many times in short period of time. It happens when db contains many rows and query including navigation property which is used in where or FirstOrDefault method.

Stack:

w lambda_method(Closure , InternalEntityEntry )
   w Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SimpleNullableDependentKeyValueFactory`1.TryCreateFromCurrentValues(InternalEntityEntry entry, TKey& key)
   w Microsoft.EntityFrameworkCore.Query.Internal.WeakReferenceIdentityMap`1.CreateIncludeKeyComparer(INavigation navigation, InternalEntityEntry entry)
   w Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.IncludeCore(Object entity, INavigation navigation)
   w Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.Include(QueryContext queryContext, Object entity, IReadOnlyList`1 navigationPath, IReadOnlyList`1 relatedEntitiesLoaders, Int32 currentNavigationIndex, Boolean queryStateManager)
   w Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.Include(QueryContext queryContext, Object entity, IReadOnlyList`1 navigationPath, IReadOnlyList`1 relatedEntitiesLoaders, Boolean queryStateManager)
   w Microsoft.EntityFrameworkCore.Query.Internal.GroupJoinInclude.Include(Object entity)
   w Microsoft.EntityFrameworkCore.Query.QueryMethodProvider.<_GroupJoin>d__26`4.MoveNext()
   w System.Linq.Enumerable.<SelectManyIterator>d__22`3.MoveNext()
   w System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   w System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
   w lambda_method(Closure , QueryContext )
   w Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass19_1`1.<CompileQuery>b__1(QueryContext qc)
   w Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
   w Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)

Operating system: Win 8.1
Environment: VS 2015 with Update 3
EF Version : "Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0"

webb_app_with_reproduced_bug
Update connection string (const in homecontroller), create migration and run in debug. Action "Get" (api/home) in home controller.

Marking for re-triage. Comment above has a repro project.

@smitpatel when we know what causes this and what a fix looks like we should consider for 1.0.1

Not able to reproduce the exception. Repro code works fine for me.

Hi, I am not sure if this is the same issue, but I get a similar error (exception below).

I have a pretty horrible linq query with multiple Include().ThenInclude() statements. It is slow it execute ~350ms. This query is executed from a core web api app and queried by an angular app. It works fine until the angular app makes multiple requests at the same time.

I have made some progress towards why there is an error. It looks like the app is trying to create another connection to the database (the app uses UseSqlServer(connection to localdb)). However the database (either by default or licencing) is set to single user so the second connection (we are processing multiple requests) fails.

captureef

I will try and post an example app that replicates the issue.

{System.NullReferenceException: Object reference not set to an instance of an object.
at lambda_method(Closure , InternalEntityEntry )
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SimpleNullableDependentKeyValueFactory1.TryCreateFromCurrentValues(InternalEntityEntry entry, TKey& key) at Microsoft.EntityFrameworkCore.Query.Internal.WeakReferenceIdentityMap1.CreateIncludeKeyComparer(INavigation navigation, InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.IncludeCore(Object entity, INavigation navigation)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.Include(QueryContext queryContext, Object entity, IReadOnlyList1 navigationPath, IReadOnlyList1 relatedEntitiesLoaders, Int32 currentNavigationIndex, Boolean queryStateManager)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.Include(QueryContext queryContext, Object entity, IReadOnlyList1 navigationPath, IReadOnlyList1 relatedEntitiesLoaders, Boolean queryStateManager)
at Microsoft.EntityFrameworkCore.Query.Internal.GroupJoinInclude.Include(Object entity)
at Microsoft.EntityFrameworkCore.Query.QueryMethodProvider.<_GroupJoin>d__264.MoveNext() at System.Linq.Enumerable.<SelectManyIterator>d__1633.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext() at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor1.EnumeratorExceptionInterceptor.MoveNext()
at System.Collections.Generic.List1..ctor(IEnumerable1 collection)
at System.Linq.Enumerable.ToListTSource
at WorkflowAPI.Managers.QuestionSetManager.GetQuestionSetSchema(Int32 questionSetId) in C:\Users\Username\Source\Workspaces\Workspace\RegistrationSolution\WorkflowAPI\Managers\QuestionSetManager.cs:line 43
at WorkflowAPI.Managers.QuestionSetManager.GetQuestionSetSchemaWithConfig(Int32 questionSetId) in C:\Users\Username\Source\Workspaces\Workspace\RegistrationSolution\WorkflowAPI\Managers\QuestionSetManager.cs:line 54
at WorkflowAPI.Managers.QuestionSetManager.GetQuestionSetWithConfigAndData(Int32 questionSetId) in C:\Users\Username\Source\Workspaces\Workspace\RegistrationSolution\WorkflowAPI\Managers\QuestionSetManager.cs:line 148
at WorkflowAPI.Controllers.QuestionSetDataController.Get(Int32 id, String filter, Int32 skip, Int32 top) in C:\Users\Username\Source\Workspaces\Workspace\RegistrationSolution\WorkflowAPI\Controllers\QuestionSetDataController.cs:line 79
at lambda_method(Closure , Object , Object[] )
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__28.MoveNext()}

@hallzhallz - Can you share stand alone repro? The stack trace says exception is coming from same location so it should be same issue. By looks of it, the hard parts of the issue would be to have a query which is sufficiently slow & call query multiple times in short span.

@smitpatel Did you run app in debug, put breakpoint in cacth statement, press and hold for a while F5 (to produce many requests) in browser on api/home?
@hallzhallz your bug is exactly the same as mine. I'm creating new context for each request "from hand" - not using registered context in IoC.

@smitpatel I've tried to reproduce the error but it is elusive thus far - I will keep trying. The error only happens for one of the methods on my controller (which makes it likely I have done something stupid).

@MarcinSzyszka - I tried that way. But there are many factors which could affect the execution like processor speed, speed of SQL instance & rate at which browser refreshes on F5 pressed. Sadly, it did not throw exception for me.

@smitpatel You are right. I have last idea how you can find this bug. Maybe try compare changes in code between RC1 and RTM in classes from stack trace. Same app with same code in Rc1 works fine but when we tried upgrade to Rtm on one machine - we got this exception everytime. I believe you can solve this issue! ;)

I have found what causes the error in my project and created a new project that replicates the issue.

The problem occurs when the model has a one-to-many object (Post) that has a navigation property to a 'parent' (Blog), but that 'many' object (Post) does not specify a property BlogId in the model (see comment in BloggingContext.cs in project).

This in itself does not cause an error but a query which includes context.Posts.Where(x=> x.Blog.Id == 3) causes the null reference exception with repeated requests (but a single request does work).

project with issue: https://github.com/hallzhallz/dotnetcore/tree/master/efcoretest
To replicate run the project go to /api/Test then click 'fetch' which will create 100 requests for /api/Values.

Let me know if anything needs clarification.

@hallzhallz - Thank you for repro project. I am able to get the exception.

Repro

[Fact]
public virtual void Test()
{

    var serviceProvider = new ServiceCollection()
        .AddEntityFrameworkSqlServer()
        .BuildServiceProvider();
    var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>()
        .UseInternalServiceProvider(serviceProvider)
        .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=efcoretest;Trusted_Connection=True;");
    var options = optionsBuilder.Options;

    using (var ctx = new BloggingContext(options))
    {
        ctx.Database.EnsureDeleted();
        ctx.Database.EnsureCreated();

        for (int i = 0; i <= 250; i++)
        {
            Blog b = new Blog();
            b.Posts = new List<Post>();

            Post p = new Post();
            b.Posts.Add(p);
            Post s = new Post();
            b.Posts.Add(s);

            ctx.Blogs.Add(b);

        }
        ctx.SaveChanges();
    }

    Parallel.For(0, 10, (i) =>
        {
            using (var ctx = new BloggingContext(options))
            {
                var result = ctx.Posts
                    .Where(x => x.Blog.Id > 1)
                    .Include(x => x.Blog)
                    .ToList();
            }
        });
}

public class BloggingContext : DbContext
{

    public BloggingContext(DbContextOptions<BloggingContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder mb)
    {
    }

    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
}

public class Blog
{
    public int Id { get; set; }

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int Id { get; set; }

    // if this id is not specified then when you query Context.Posts.Blog.Id the query fails with Null Reference Exception
    //public int BlogId { get; set; }
    public Blog Blog { get; set; }
}
Was this page helpful?
0 / 5 - 0 ratings