dotnet / dotnet/EntityFramework.Docs
FirstOrDefault() returning null in .NET 6 but empty object in .NET Core 3
- Dominant language
- Mermaid
- Stars
- 1.7k
- Forks
- 2k
- Avg merge
- 7d 23h
- Merged PRs (30d)
- 16
Description
We are in the process of migrating our app from .NET Core 3.1.28 to .NET 6.0.8
So far the transition has been pretty painless, but we've found an annoying case where we get an `InvalidOperationException` when using FirstOrDefault() and immediately calling a value on the result.
In .NET Core 3, FirstOrDefault() returned an empty object initialized with default values, and the query worked fine
In .NET 6, the same query now returns `null` and the query logically crashes
Here is a (very) simplified repro of our use case. There are of course workarounds, but I'd like to know if this change was intended or if it is a regression.
```csharp
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace FirstOrDefaultBehavior
{
class Program
{
static void Main(string[] args)
{
using (var context = new MyContext())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
context.Item.Add(new Item() { Code = 1 });
context.Item.Add(new Item() { Code = 2 });
context.SaveChanges();
context.StockMovement.Add(new StockMovement() { ItemFk = context.Item.First().Id });
context.SaveChanges();
// Always works since Item 1 has attached StockMovement
var ok = context.Item
.Where(i => i.Code == 1)
.Select(i => new
{
i.Id,
i.Code,
SomeStockValue = i.StockMovement.FirstOrDefault().ItemFk
})
.ToList();
// Crashes in .Net 6, worked fine in .Net Core 3.1
var crash = context.Item
.Where(i => i.Code == 2)
.Select(i => new
{
i.Id,
i.Code,
SomeStockValue = i.StockMovement.FirstOrDefault().ItemFk
})
.ToList();
}
}
}
public class MyContext : DbContext
{
public virtual DbSet Item { get; set; }
public virtual DbSet StockMovement { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
string connectionString = "Server=.;Database=FirstOrDefaultBehavior;Trusted_Connection=True;MultipleActiveResultSets=true";
optionsBuilder.UseSqlServer(connectionString)
.EnableSensitiveDataLogging()
.UseLoggerFactory(new LoggerFactory());
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity(entity =>
{
entity.HasIndex(e => e.Code, "UK_Item_Code")
.IsUnique();
entity.Property(e => e.Id).HasColumnName("id");
});
modelBuilder.Entity(entity =>
{
entity.Property(e => e.Id).HasColumnName("id");
entity.Property(e => e.ItemFk).HasColumnName("item_fk");
entity.HasOne(d => d.ItemFkNavigation)
.WithMany(p => p.StockMovement)
.HasForeignKey(d => d.ItemFk)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_StockMovement_Item");
});
}
}
public partial class Item
{
public Item()
{
StockMovement = new HashSet();
}
public int Id { get; set; }
public int Code { get; set; }
public virtual ICollection StockMovement { get; set; }
}
public partial class StockMovement
{
public StockMovement()
{
InverseParentFkNavigation = new HashSet();
}
public int Id { get; set; }
public int ItemFk { get; set; }
public virtual ICollection InverseParentFkNavigation { get; set; }
public virtual Item ItemFkNavigation { get; set; }
}
}
```
Result in .NET 6 :
```
Unhandled exception. System.InvalidOperationException: Nullable object must have a value.
at lambda_method7(Closure , QueryContext , DbDataReader , ResultContext , SingleQueryResultCoordinator )
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at FirstOrDefaultBehavior.Program.Main(String[] args) in C:\Users\FirstOrDefaultBehavior\Program.cs:line 37
```
Result in .NET Core 3 :
No crash, the value of `SomeStockValue` in case 2 is `0`
### Include provider and version information
EF Core version: 6.0.8
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 6.0.8
Operating system: Windows 10 x64
IDE: Visual Studio 2022
Contributor guide
Assessment
This issue has not been assessed yet.