实体框架ChangeTracker流并随后保存到查询 [英] Entity Framework ChangeTracker Stream and Save to Query Afterwards

查看:158
本文介绍了实体框架ChangeTracker流并随后保存到查询的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想验证何时在实体框架(带有数据库)中修改/更新/插入/删除了某些实体。 (例如ProductType实体表)

I want to validate when certain Entity is Modified/Updated/Inserted/Deleted in Entity Framework (with database). (eg ProductType Entity table)

**希望以后保存并查询Change Tracker,因为如果在DbContext对象之前未保存跟踪更改,则会丢失跟踪更改只需将ChangeTracker保留最多几个小时即可进行分析,并在需要时保存在MessageQueue中。内存缓存也可以工作。

** Would like Change Tracker to be saved and queried later, as 'the track changes are lost if they are not saved before the DbContext object is destroyed.' Only need ChangeTracker to be retained for couple hours most to analyze, and be saved in MessageQueue if needed. MemoryCache can also work.

1)
有人建议使用LoggerFactory:

1) Someone recommend using LoggerFactory:

optionsBuilder.UseLoggerFactory(loggerFactory) 

https://www.entityframeworktutorial.net/efcore/logging-in-entityframework-core.aspx

但是,很难进行解析,因为更新,修改,删除可以通过Join,别名,方括号以及EF经常生成的复杂SQL语句来完成。因此,文本解析可能不准确。

However, it can be hard to parse as updates, modifications, deletes can be done with a Join, aliases, brackets, with intricate SQL statements often generated by EF. So text parsing may not be accurate.

INSERT INTO [Students] ([DateOfBirth], [GradeId], [Height], [Photo], [Stud
entName], [Weight])
VALUES (@p0, @p1, @p2, @p3, @p4, @p5);
SELECT [StudentID]
FROM [Students]
WHERE @@ROWCOUNT = 1 AND [StudentID] = scope_identity();
info: Microsoft.EntityFrameworkCore.Database.Command[200101]
Executed DbCommand (68ms) [Parameters=[@p0='' (DbType = DateTime2), @p1=''
(DbType = Int32), @p2='0', @p3='' (Size = 8000) (DbType = Binary), @p4='Steve'
(Size = 4000), @p5='0'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
INSERT INTO [Students] ([DateOfBirth], [GradeId], [Height], [Photo], [Stud
entName], [Weight])
VALUES (@p0, @p1, @p2, @p3, @p4, @p5);
SELECT [StudentID]
FROM [Students]
WHERE @@ROWCOUNT = 1 AND [StudentID] = scope_identity();
A data reader was disposed.
dbug: Microsoft.EntityFrameworkCore.Database.Transaction[2002

2)选项2是ChangeTracker ,
其他建议在 SaveChanges 语句之前使用ChangeTracker,因为它更简洁(请参见下面的查询)。但是,在每个SaveChanges语句之前执行此操作,考虑到每秒有500个事务,这会影响应用程序的性能速度。

2) Option 2 is ChangeTracker, Others recommended using ChangeTracker before SaveChanges statement, because its much cleaner (see below query). However executing this before every SaveChanges statement, considering we have 500 transactions /per second affects application performance speed.

因此,有什么方法可以将ChangeTracker历史记录流化并保留到日志中保存更改后,哪里可以更轻松地查询更改了哪些实体?

So is there any method to stream and retain ChangeTracker history to a log after save changes, where one can query easier what entities changed? Its optimal to find out after transaction is complete, without blocking transactions.

var Entries = context.ChangeTracker
           .Entries()
           .Where(x => x.State == EntityState.Modified || x.State == EntityState.Deleted|| x.State == EntityState.Added)
           .Select(x =>x.Entity)
           .ToList();

https://entityframework.net/change-tracker

推荐答案

@DerrikRodgers,检查所需时间如果Entity是某个类型的实例,则该时间与交易时间不可比。拥有您提供的代码,每秒500笔交易绝对可以正常工作。

@DerrikRodgers, time required to check if Entity is an instance of a certain type is not comparable to a transaction time. 500 transactions/second will work absolutely fine having code you provided.

public void ReportChanges()
{
  var entities=ChangeTracker
           .Entries()
           .Where(x => x.Entity is Product)
           .Where(x => x.State == EntityState.Modified || x.State == EntityState.Deleted || x.State == EntityState.Added)
           .GroupBy(x=>x.State, x => x.Entity as Product)
           .ToList();
  ... // Producer/Consumer to do not block current thread and control concurrency
}

通过综合测试获取性能基准,如下所示:

Get performance baseline with a synthetic test, something like this:

var cc = new ApplicationDbContext();
for (int i = 0; i < 100; i++)
    cc.Users.Add(new ApplicationUser() { Id = i });

var sw = Stopwatch.StartNew();
for (int i = 0; i < 1000; i++)
    cc.ReportChanges();
sw.Stop();
Console.WriteLine($"1000 times to report 100 entities took {sw.ElapsedMilliseconds}ms. Rate {1000*100/(sw.ElapsedMilliseconds/1000.0)} items/s");
Console.ReadKey();

// 1000 times to report 100 entities took 461ms. Rate 216919.739696312 items/s

另一个问题是您将如何处理过滤后的实体。那东西可能很慢。例如,如果您尝试全部记录它们,并且在记录器中不使用异步接收器/目标,则速度会很慢。在这种情况下,您可以实现生产者/消费者将过滤后的实体进行模式化和管道传输到另一个使用者,后者将在另一个线程中分派它们并执行较长的操作。在这种情况下, Rx.NET 可能会非常有用。

Another question is what you are going to do with the filtered entities. That thing might be slow. For example if you'll try to log them all and you don't use asynchronous sinks/targets in your logger, this will be slow. In this case you can implement Producer/Consumer pattern and pipe filtered entities to another consumer which will dispatch them in a different thread and do something long. Rx.NET might be very helpful in this case.

代替生产者/消费者,您可以启动 Task ,但是这可能导致线程池不足,我d建议明确控制慢速操作的并行性。

Instead of producer/consumer you can just start a Task, but that might lead to thread pool starvation and I'd recommend explicitly control parallelism of your 'slow' operations.

这篇关于实体框架ChangeTracker流并随后保存到查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆