dotnet / dotnet/efcore

Partially tracking queries

Open
#29,756 4 comments 1 reaction 0 assignees View on GitHub
area-query customer-reported needs-design
Dominant language
C#
Stars
14.8k
Forks
3.4k
PR merge metrics
PR metrics pending

Description

We are trying to migrate NHibernate to EfCore 7 our huge banking project that contains 1500 entities and those mappings, consider allowing AsNoTracking or AsNoTrackingWithIdentityResolution via navigations, with this behaviour we could able to query only properties through configuration file.,

Consider following example is it possible, If we access Blogs through BlogOwner we dont want to track those instances. But if we access throug DbSet or any other entity that does not implies "AsNoTracking or AsNoTrackingWithIdentityResolution" must be trackable default now all navigation or collections are trackable.

Is it possible to handle this via [IQueryExpressionInterceptor](https://github.com/dotnet/efcore/blob/main/src/EFCore/Diagnostics/IQueryExpressionInterceptor.cs), in interceptor we need to find out any parent entity configurations that has AsNoTracking* or not? And could we apply AsNoTracking or AsNoTrackingWithIdentityResolution if its not already applied?

```c#
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Sample
{
class Program
{
static void Main(string[] args)
{
using (var db = new BloggingContext())
{
db.Database.EnsureCreated();

db.BlogOwners.ForEach(x=>x.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/adonet" }));
var count = db.SaveChanges();
Console.WriteLine("{0} records saved to database", count);
}
}
}

public class BloggingContext : DbContext
{
public DbSet BlogOwners { get; set; }
public DbSet Blogs { get; set; }
public DbSet Posts { get; set; }

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Sample;Trusted_Connection=True;");
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity().HasOne(x=>x.Blog).WithMany().AsNoTracking();
modelBuilder.Entity().HasMany(x=>x.Posts).WithOne(x=>x.Blog);
}
}

public static class Extensions
{
private static readonly string AsNoTracking = "custom:asNoTracking";
private static readonly string AsNoTrackingWithIdentityResolution = "custom:asNoTrackingWithIdentityResolution";

public static ReferenceCollectionBuilder AsNoTracking (
this ReferenceCollectionBuilder builder)
where TPrincipalEntity : class
where TDependentEntity : class
{
builder.Metadata.PrincipalToDependent?.SetAnnotation(AsNoTracking , true);

return builder;
}

public static ReferenceCollectionBuilder AsNoTrackingWithIdentityResolution (
this ReferenceCollectionBuilder builder)
where TPrincipalEntity : class
where TDependentEntity : class
{
builder.Metadata.PrincipalToDependent?.SetAnnotation(AsNoTrackingWithIdentityResolution , true);

return builder;
}
}

public class BlogOwner
{
public int OwnerId{ get; set; }
public int BlogId { get; set; }
public string OwnerEmail{ get; set; }

public Blog Blog { get; set; }
}

public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }

public List Posts { get; set; }
}

public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }

public int BlogId { get; set; }
public Blog Blog { get; set; }
}
}
```

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.