Skip to content
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

Partially tracking queries #29756

Open
gokhanabatay opened this issue Dec 4, 2022 · 4 comments
Open

Partially tracking queries #29756

gokhanabatay opened this issue Dec 4, 2022 · 4 comments

Comments

@gokhanabatay
Copy link

gokhanabatay commented Dec 4, 2022

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, 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?

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<BlogOwner> BlogOwners { get; set; }
        public DbSet<Blog> Blogs { get; set; }
        public DbSet<Post> 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<BlogOwner>().HasOne(x=>x.Blog).WithMany().AsNoTracking();
            modelBuilder.Entity<Blog>().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<TPrincipalEntity, TDependentEntity> AsNoTracking <TPrincipalEntity, TDependentEntity>(
            this ReferenceCollectionBuilder<TPrincipalEntity, TDependentEntity> builder)
            where TPrincipalEntity : class
            where TDependentEntity : class
        {
            builder.Metadata.PrincipalToDependent?.SetAnnotation(AsNoTracking , true);

            return builder;
        }

 public static ReferenceCollectionBuilder<TPrincipalEntity, TDependentEntity> AsNoTrackingWithIdentityResolution <TPrincipalEntity, TDependentEntity>(
            this ReferenceCollectionBuilder<TPrincipalEntity, TDependentEntity> 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<Post> 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; }
    }
}
@ajcvickers
Copy link
Member

@gokhanabatay I don't really understand what you are trying to do. Is the intention to get a connected graph of entities but prevent updates to some entities in the graph? If so, that's tracked by issue #29719, but it's unlikely to be implemented by not tracking those entities.

@gokhanabatay
Copy link
Author

@ajcvickers our intention is to migrate ef core but keep our business logic as same as possible. With NHibernate we can define relation readonly/query only in some graph.

Let me explain another example:

Student -> Has Many Childrens -> Has One Country, Country is query only/readonly reference property in this graph.

Country -> Has Many City, Country is not query only/readonly in this graph.

@gokhanabatay
Copy link
Author

Hi @ajcvickers what dou you think?

@ajcvickers our intention is to migrate ef core but keep our business logic as same as possible. With NHibernate we can define relation readonly/query only in some graph.

Let me explain another example:

Student -> Has Many Childrens -> Has One Country, Country is query only/readonly reference property in this graph.

Country -> Has Many City, Country is not query only/readonly in this graph.

@ajcvickers
Copy link
Member

@gokhanabatay I think read-only navigations is something we can consider, probably as part of #29719. Make sure to vote (👍) for that issue.

@ajcvickers ajcvickers changed the title ReadOnly - AsNoTracking Navigation property(Collection or Reference) Partially tracking queries Dec 8, 2022
@ajcvickers ajcvickers added this to the Backlog milestone Dec 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants