dotnet / dotnet/EntityFramework.Docs

FirstOrDefault() returning null in .NET 6 but empty object in .NET Core 3

Open
#3,983 4 comments 0 reactions 0 assignees View on GitHub
area-query
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.