Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query: Threading issues cause NullReferenceException in SimpleNullableDependentKeyValueFactory #5456

Closed
alexlau811 opened this issue May 21, 2016 · 25 comments
Assignees
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Milestone

Comments

@alexlau811
Copy link

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()<---
<---
<---
<---
<---
<---
@smitpatel smitpatel changed the title System.NullReferenceException: Object reference not set to an instance of an object. System.NullReferenceException in SimpleNullableDependentKeyValueFactory May 21, 2016
@smitpatel smitpatel changed the title System.NullReferenceException in SimpleNullableDependentKeyValueFactory NullReferenceException in SimpleNullableDependentKeyValueFactory May 21, 2016
@rowanmiller rowanmiller added this to the 1.0.0 milestone May 23, 2016
@ajcvickers
Copy link
Member

@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?

@alexlau811
Copy link
Author

@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

@ajcvickers
Copy link
Member

@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.

@rowanmiller rowanmiller removed this from the 1.0.0 milestone May 31, 2016
@rowanmiller
Copy link
Contributor

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

@michaelroef
Copy link

michaelroef commented Jun 9, 2016

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()`
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
        }
    }
}

@ajcvickers
Copy link
Member

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

@ajcvickers ajcvickers reopened this Jun 9, 2016
@ajcvickers ajcvickers removed their assignment Jun 9, 2016
@divega
Copy link
Contributor

divega commented Jun 10, 2016

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:

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

}

@tennlos
Copy link

tennlos commented Jun 18, 2016

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.

@ajcvickers
Copy link
Member

@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?

@tennlos
Copy link

tennlos commented Jun 20, 2016

@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

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:

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

        }

@ajcvickers
Copy link
Member

@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.

@tennlos
Copy link

tennlos commented Jun 20, 2016

@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:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> 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:

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

@MarcinSzyszka
Copy link

MarcinSzyszka commented Jul 1, 2016

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.

@ajcvickers
Copy link
Member

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

@ajcvickers ajcvickers reopened this Jul 5, 2016
@ajcvickers ajcvickers removed their assignment Jul 5, 2016
@rowanmiller rowanmiller added this to the 1.0.1 milestone Jul 5, 2016
@rowanmiller
Copy link
Contributor

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

@rowanmiller rowanmiller removed the pri0 label Jul 6, 2016
@smitpatel
Copy link
Member

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

@hallzhallz
Copy link

hallzhallz commented Jul 13, 2016

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.ToList[TSource](IEnumerable`1 source)
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()}

@smitpatel
Copy link
Member

@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.

@MarcinSzyszka
Copy link

@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.

@hallzhallz
Copy link

@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).

@smitpatel
Copy link
Member

@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.

@MarcinSzyszka
Copy link

@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! ;)

@hallzhallz
Copy link

hallzhallz commented Jul 13, 2016

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.

@smitpatel
Copy link
Member

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

@smitpatel
Copy link
Member

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

@rowanmiller rowanmiller changed the title NullReferenceException in SimpleNullableDependentKeyValueFactory Threading Related Crash: NullReferenceException in SimpleNullableDependentKeyValueFactory Jul 21, 2016
@smitpatel smitpatel added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Jul 22, 2016
@divega divega changed the title Threading Related Crash: NullReferenceException in SimpleNullableDependentKeyValueFactory Query: Threading issues cause NullReferenceException in SimpleNullableDependentKeyValueFactory Sep 13, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Projects
None yet
Development

No branches or pull requests

10 participants