-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Make EntityEntryGraphIterator publicly usable #26461
Comments
Ended up having such implementation (not tested yet): private bool GraphHasChanges(TAggregateRoot aggregateRoot) => GraphHasChangesRecursive(aggregateRoot, new HashSet<object>());
private bool GraphHasChangesRecursive(object rootEntity, HashSet<object> checkedEntities)
{
// prevents cycles.
if (checkedEntities.Contains(rootEntity))
{
return false;
}
var rootEntityEntry = _dbContext.Entry(rootEntity);
if (rootEntityEntry.State == EntityState.Detached)
{
throw new InvalidOperationException($"Root entity of type '{rootEntity.GetType()}' is not tracked.");
}
checkedEntities.Add(rootEntityEntry);
if (rootEntityEntry.State != EntityState.Unchanged)
{
return true;
}
var changesInChildEntities = rootEntityEntry.Navigations.Any(_ => _.IsModified || _.CurrentValue switch
{
IEnumerable seq => seq.OfType<object>().Any(entity => GraphHasChangesRecursive(entity, checkedEntities)),
object entity => GraphHasChangesRecursive(entity, checkedEntities)
});
if (changesInChildEntities)
{
return true;
}
return false;
} |
@voroninp Have you considered using the |
@ajcvickers I was not aware of it, thanks. Should I resolve it with service provider, or is it accessible through DbContext? |
handleNode: Func<EntityEntryGraphNode<TState>,Boolean> Is returned bool for signaling whether to continue traversal? |
|
you won't get rid of me that easy =) Constructor of EntityEntryGraphNode has this documentation:
And not much about its arguments. =( |
@voroninp Don't call the constructor. Use CreateNode. |
Where can |
@voroninp You are right. We should look into making this available publicly. For now, you can use TrackGraph, without actually tracking anything. Here's an example, based on this test: public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Post> Posts { get; } = new List<Post>();
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public Blog Blog { get; set; }
}
public class SomeDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlServer(Your.ConnectionString)
//.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
public virtual DbSet<Blog> Blogs { get; set; }
}
public class Program
{
public static void Main()
{
using (var context = new SomeDbContext())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
context.Add(new Blog {Posts = {new(), new()}});
context.SaveChanges();
}
using(var context = new SomeDbContext())
{
var blog = context.Blogs.Include(e => e.Posts).Single();
var visited = new HashSet<object>();
var traversal = new List<string>();
context.ChangeTracker.TrackGraph(
blog,
visited,
node =>
{
if (node.NodeState.Contains(node.Entry.Entity))
{
return false;
}
node.NodeState.Add(node.Entry.Entity);
traversal.Add(NodeString(node));
return true;
});
foreach (var visit in traversal)
{
Console.WriteLine(visit);
}
}
}
private static string NodeString(EntityEntryGraphNode node)
=> EntryString(node.SourceEntry)
+ " ---"
+ node.InboundNavigation?.Name
+ "--> "
+ EntryString(node.Entry);
private static string EntryString(EntityEntry entry)
=> entry == null
? "<None>"
: entry.Metadata.DisplayName()
+ ":"
+ entry.Property(entry.Metadata.FindPrimaryKey().Properties[0].Name).CurrentValue;
} Output:
|
Thanks, guys! |
Currently
EntityEntryGraphNode
constructor is internal and depends on internal types.I want to automatically change concurrency token of an aggregate root when any of its entities changes.
It's is possible that AR entity has no changes, but child entities do. So I'd like to traverse the graph and check whether there are modified, added, or deleted entities. And if yes,
Version
property should be incremented.There's is a
TrackGraph
method to adjust tracking for disconnected entities, but I want to traverse already attached graph. Do I have to write this functionality myself usingEntityEntry
api for accessing navigations?I am also curious how I detect additions and removals of child entities? Is
NavigationEntry.IsModified
enough for this?The text was updated successfully, but these errors were encountered: