dotnet / dotnet/EntityFramework.Docs
Document that identity resolution does not apply to instances explicitly created with new
- Dominant language
- Mermaid
- Stars
- 1.7k
- Forks
- 2k
- Avg merge
- 7d 23h
- Merged PRs (30d)
- 16
Description
If I use AsNoTracking with IdentityResolution in combination with a projection in where a reference navigation property is also projected, then IdentityResolution doesn't work: Multiple principal instances will be created for entities having the same primary key.
If the referenced navigation property is NOT projected it works as expected.
### Example
In my example (full working UnitTest see below) I've got an 'OrderPosition' containing a reference navigation 'Article'.
There're two order positions in database that each have a reference to the same (only) Article that exists.
This leads EFCore to create only one Article instance that is then referenced by both the positions (as expected):
```C#
var positions = ctx.OrderPosition.Select(
op => new OrderPosition() {
OrderPositionId = op.OrderPositionId,
Article = op.Article
})
.AsNoTrackingWithIdentityResolution()
.ToList();
```
But this leads EFCore to create TWO Article instances (what I think is wrong):
```C#
var positions = ctx.OrderPosition.Select(
op => new OrderPosition() {
OrderPositionId = op.OrderPositionId,
Article = new Article() {
ArticleId = op.ArticleId,
Description = op.Description
}
})
.AsNoTrackingWithIdentityResolution()
.ToList();
```
### The complete example (UnitTest)
```C#
using System.Linq;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Xunit;
namespace EFCore.Issue {
class MyContext(DbContextOptions options) : DbContext(options) {
public DbSet OrderPosition { get; set; }
public DbSet Article { get; set; }
}
class OrderPosition {
public int OrderPositionId { get; set; }
public string? Description { get; set; }
public int ArticleId { get; set; }
public Article? Article { get; set; }
}
class Article {
public int ArticleId { get; set; }
public string? Description { get; set; }
}
public class TestIdentityResolution {
private static DbContextOptions CreateOptions() where T : DbContext {
var connectionStringBuilder = new SqliteConnectionStringBuilder { DataSource = ":memory:" };
var connectionString = connectionStringBuilder.ToString();
var connection = new SqliteConnection(connectionString);
if (connection.State != System.Data.ConnectionState.Open) {
connection.Open();
}
var builder = new DbContextOptionsBuilder();
builder.UseSqlite(connection);
return builder.Options;
}
static MyContext CreateContext() {
var options = CreateOptions();
FillData(options);
return new MyContext(options);
static void FillData(DbContextOptions options) {
var dbContext = new MyContext(options);
dbContext.Database.EnsureDeleted();
dbContext.Database.EnsureCreated();
dbContext.Article.Add(new Article { ArticleId = 99, Description = "Some article" });
dbContext.OrderPosition.Add(new OrderPosition() {
OrderPositionId = 1,
Description = "Order pos 1",
ArticleId = 99
});
dbContext.OrderPosition.Add(new OrderPosition() {
OrderPositionId = 2,
Description = "Order pos 2",
ArticleId = 99
});
dbContext.SaveChanges();
}
}
[Fact]
public void Projection() {
var ctx = CreateContext();
var positions = ctx.OrderPosition.Select(
op => new OrderPosition() {
OrderPositionId = op.OrderPositionId,
Article = op.Article
})
.AsNoTrackingWithIdentityResolution()
.ToList();
var pos1Art = positions[0].Article;
var pos2Art = positions[1].Article;
Assert.Equal(pos1Art, pos2Art);
}
[Fact]
public void ProjectionAlsoReferenceProjected() {
var ctx = CreateContext();
var positions = ctx.OrderPosition.Select(
op => new OrderPosition() {
OrderPositionId = op.OrderPositionId,
Article = new Article() {
ArticleId = op.ArticleId,
Description = op.Description
}
})
.AsNoTrackingWithIdentityResolution()
.ToList();
var pos1Art = positions[0].Article;
var pos2Art = positions[1].Article;
Assert.Equal(pos1Art, pos2Art);
}
}
}
```
ProjectFile
```csproj
net8.0
enable
Nullable
false
net8.0-windows
all
runtime; build; native; contentfiles; analyzers; buildtransitive
```
### Used provider and versions
EF Core version: 8.0.1
Database provider: Microsoft.EntityFrameworkCore.Sqlite | Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 8.0
Operating system: Win 10.0.19044.3086]
IDE: Visual Studio 2022 17.8.4
Contributor guide
Assessment
This issue has not been assessed yet.