【问题标题】:Serialize EF Core InMemory Database to JSON将 EF Core InMemory 数据库序列化为 JSON
【发布时间】:2019-01-25 02:18:28
【问题描述】:

我期待在 DbContext 中提取大量实体的增量更改,并将实际的 DB 提交委托给后台进程,例如 Azure Web 作业。

尝试过,但无法序列化。

        var deltaJson = "";
        try
        {
            var modifiedEntries = _ctx.ChangeTracker
                .Entries()
                .Select(x => x.Entity)
                .ToList();
            deltaJson = JsonConvert.SerializeObject(modifiedEntries, Formatting.Indented);
        }

我的下一个希望是使用内存数据库,如果可以的话 序列化 DbContext 的整个对象图。

可行吗?您的专家建议和这方面的任何指示都会非常有帮助。

编辑: 我自己的版本:

public class DeltaTracking
{
    public static List<T> Build<T>(ICollection<T> db, ICollection<T> req) where T : IR
    {
        return Build(db, req, new DT<T>());
    }

    public static List<T> Build<T>(ICollection<T> db, ICollection<T> req, IEqualityComparer<T> comp) where T : IStateTracking
    {
        db = db ?? new List<T>();
        req = req ?? new List<T>();

        List<T> added = req.Except(db, comp).ToList();
        foreach (T a in added)
        {
            a.State = TrackingState.Added.ToString();
        }

        List<T> removed = db.Except(req, comp).ToList();
        foreach (T r in removed)
        {
            r.State = TrackingState.Deleted.ToString();
        }

        List<T> unchanged = db.Intersect(req, comp).ToList();
        foreach (T u in unchanged)
        {
            u.State = TrackingState.Unchanged.ToString();
        }
        List<T> resp = added.Union(removed, comp).Union(unchanged, comp).ToList();
        return resp;
    }
}

【问题讨论】:

  • 您遇到的具体问题是什么?为什么不能序列化?记忆?其他问题?

标签: c# json entity-framework entity-framework-core ef-core-2.0


【解决方案1】:

您可以从更改跟踪器中序列化实体,但是鉴于这听起来您想要序列化和卸载大量更改,您可能需要将更改打包到较小的页面中,通过网络传输它们,跟踪和编写另一端的变更集,并确保它们按顺序重新组合,因为变更集将跨越相关实体。

const int pageSize = 1000;
var count = context.ChangeTracker.Entries()
    .Count(x => x.State == EntityState.Modified || x.State == EntityState.Added || x.State == EntityState.Deleted);

var pages = (int) Math.Ceiling((double) count / PageSize);
int loopCounter = 0;
while (loopCounter < pages)
{
   var changes = context.ChangeTracker.Entries()
      .Where(x => x.State == EntityState.Modified || x.State == EntityState.Added || x.State == EntityState.Deleted)
      .Select(x => new { Type = x.Entity.GetType(), State = x.State.ToString(), Original = x.OriginalValues.ToObject(), Updated = x.CurrentValues.ToObject() })
      .Skip(loopCounter * pageSize)
      .Take(pageSize);

   var data = new
   {
      PageNumber = loopCounter,
      Changes = changes,
   };

   string changeData = JsonConvert.SerializeObject(data, Formatting.Indented);
   // Fire across to destination to be processed. Be sure to send the total # of pages because the server cannot start processing these unless they are in order.

.Changes 将包含类型、状态(采取什么操作、更新、添加、删除)以及适用的原始和更新实体值。

如果这只是处理批量更新,则排除添加/删除项目并让它们通过。

在接收方,我不相信它会像获取更改的实体并将它们附加到 DbContext 以保持更新一样简单。这些可能需要由目标 DbContext 加载并根据附加实体中的字段进行更新。需要做一些工作来提取诸如删除操作的 PK 之类的东西。添加应该非常简单。

另一个真正的测试是更改发生时间和后台服务运行它们之间的并发性。您应该考虑检查版本控制是否有任何更新。这可能不是一个完整的解决方案,但希望它能提供一些想法或引发一些讨论。

【讨论】:

    【解决方案2】:

    总是可以通过消息传递(MSMQ,RabbitMQ)做一些事情。您的进程一次将一个“事务”发布到队列,而侦听器一次处理一个,完全异步。可以从接收方生成多个进程以获得更好的吞吐量。

    更新:消息队列还处理更新序列,同时保持异步。

    【讨论】:

      猜你喜欢
      • 2017-10-19
      • 2021-04-20
      • 1970-01-01
      • 1970-01-01
      • 2021-12-17
      • 2016-12-17
      • 1970-01-01
      • 1970-01-01
      • 2021-01-08
      相关资源
      最近更新 更多