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
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? |
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 |
@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'm using Entity Framework Core RC2.
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: 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 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);
}
} |
@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 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; }
} |
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:
Operating system: Win 8.1 webb_app_with_reproduced_bug |
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. I will try and post an example app that replicates the issue.
|
@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? |
@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 Let me know if anything needs clarification. |
@hallzhallz - Thank you for repro project. I am able to get the exception. |
Repro
|
I am getting random crash when getting the list but not sure why.
Here is the exception log:
The text was updated successfully, but these errors were encountered: