C# WPF 实体框架 6 同步数据库

本文关键字:同步 数据库 框架 WPF 实体 | 更新日期: 2023-09-27 17:56:47

>场景:

我有两个MySQL数据库:

  1. 大主数据库
  2. 小型客户端数据库

示例表:

大数据库用户:

文本用户名

  • 整数标识
  • 瓦尔查尔登录
  • 瓦尔查尔密码
  • 。更多字段

客户端数据库用户

  • 整数标识
  • int 唯一api_id(来自主节点的 ID)
  • 瓦尔查尔登录
  • 瓦尔查尔密码

问题:我需要同步数据库,但我不知道如何以最佳方式执行此操作。我读了这个问题,但它很旧,没有涵盖我的情况。我通过 REST API 与主数据库通信,直接连接不是选项。

我的同步算法

  • 将数据从 REST API 下载并反序列化(例如/api/users/)到 ApiUser 对象列表
   公共类 ApiUser {      整数 ID;      字符串登录;      字符串密码;    }    公共类用户{      整数 ID;      国际api_id;      字符串登录;      字符串密码;    }
  • 迭代 API 用户列表
    • 如果存在 ApiUser.id 实体,则覆盖所有字段
    • 否则创建新实体
  • 保存更改

我的代码:

public void syncUsers(List  ApiUsers)    {        using (var db = new dbEntities())        {            ApiUsers.ForEach(apiUser =>            {                var dbUser = db.client                    .其中(c => c.api_id == apiUser.id)                    .SingleOrDefault();                if (dbUser == null)                {                    var userObj = new user()                    {                        api_id = apiUser.id,                        login = apiUser.login,                        密码 = apiUser.password                    };                    db.client.Add(userObj);                }                还                {                    dbUser.api_id = apiUser.id,                    dbUser.login = apiUser.login,                    dbUser.password = apiUser.password                }            });            .db。保存更改();        }    }

问题:如何做得更好?我对从 master 数据库中删除实体有问题,我的算法没有涵盖这种情况。

C# WPF 实体框架 6 同步数据库

我假设所有用户的交互或自动事务仅在 master 数据库中完成(否则您将需要某种合并复制,这并非易事)。

至于已删除的实体,有几个选项。在任何情况下,master 数据库都必须将有关已删除实体的信息传播到客户端数据库。

1.如果信息被删除,则每个实体都持有该信息。

在这种情况下,可以使用软删除选项,该选项可以通过重写 DbContext 的 OnModelCreate 和 SaveChanges 方法在 EF 中轻松实现(可以在网络上找到许多实现的代码示例)。此选项也有一些缺点 - 您可能具有相当复杂的域模型,其中包含实体之间的关系,因此在删除父实体时必须注意软删除子实体。如果主数据库和客户端数据库有不同的前端应用程序,则必须升级所有这些前端应用程序,才能将新的软删除属性(例如 IsDeleted)付诸行动。但是在这种情况下,(软)删除实体的同步本身非常简单,因为它只需要在客户端更新一个附加属性。

2. 已删除实体的新表。

在这种情况下,您必须为每个实体创建一个附加表并插入 Id 值,然后再删除任何实体。您必须覆盖 DbContext 的 SaveChanges 才能拦截处于 EntityState.Delete 状态的实体。


关于第一个问题,这取决于您要增强什么。如果您希望表中有许多记录,则应考虑引入其他字段以仅更新在 master 数据库中真正更新的记录 - 您可以分别在 int(实体版本)、DateTime 或 guid 值之间进行选择,具体取决于最适合您的情况。

如果要分离处理逐个属性更新的关注点,则可以仅出于同步目的创建特殊的实体模型,将数据反序列化为这些对象,然后使用AutoMapper更新对象,例如:

更新

dbUser = Mapper.Map<User>(apiUser);
db.Set<User>().Attach(dbUser);
db.Entry(dbUser).State = EntityState.Modified;
db.SaveChanges();

dbUser = Mapper.Map<User>(apiUser);
db.client.Add(dbUser)
db.SaveChanges();