将EF Core InMemory数据库序列化为JSON

时间:2018-08-18 05:27:56

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

Azure Web作业,我期待在DbContext中提取大量的实体变化,并将实际的数据库提交委托给后台进程。

尝试过此操作,但无法序列化。

        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;
    }
}

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的Delete操作。添加内容应该非常简单。

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

答案 1 :(得分:-1)

总是可以横着走,用Messaging(MSMQ,RabbitMQ)做某事。您的流程一次将一个“事务”发布到队列中,而侦听器则一次完全异步地处理一个事务。可以从接收方生成多个进程以提高吞吐量。

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