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

gre*_*ort 6 c# wpf synchronization entity-framework

场景:

我有两个MySQL数据库:

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

示例表:

大数据库用户:

文字用户名

  • int id
  • varchar登录
  • varchar密码
  • ......还有很多领域

客户数据库用户

  • int id
  • int UNIQUE api_id (来自master的id)
  • varchar登录
  • varchar密码

问题: 我需要同步数据库,但我不知道如何以最好的方式做到这一点.我读过这个问题,但它已经很老了,并没有涵盖我的情况.我通过REST API与master数据库通信,直接连接不是选项.

我的同步算法

  • 从REST API下载数据并将其反序列化(例如/ api/users /)到ApiUser对象列表

    public class ApiUser {
      int id;
      string login;
      string password; 
    }

    public class User{
      int id;
      int api_id;
      string login;
      string password; 
    }

  • 迭代Apiusers列表
    • 如果存在具有ApiUser.id的实体,则覆盖所有字段
    • 否则创建新实体
  • 保存更改

我的代码:

public void syncUsers(List <ApiUser> ApiUsers)

    {
        using (var db = new dbEntities())
        {
            ApiUsers.ForEach(apiUser =>
            {
                var dbUser = db.client
                    .Where(c => c.api_id == apiUser.id)
                    .SingleOrDefault();

                if (dbUser == null)
                {
                    var userObj = new user()
                    {
                        api_id = apiUser.id,
                        login = apiUser.login,
                        password = apiUser.password
                    };
                    db.client.Add(userObj);
                }
                else
                {
                    dbUser.api_id = apiUser.id,
                    dbUser.login = apiUser.login,
                    dbUser.password = apiUser.password
                }

            });

            db.SaveChanges();
        }
    }

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

Tom*_*vec 1

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

对于已删除的实体,有多种选择。无论如何,您的主数据库必须将有关已删除实体的信息传播到客户端数据库。

1. 如果信息被删除,每个实体都会保留该信息。

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

2. 已删除实体的新表。

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


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

如果您想单独处理逐个属性更新的问题,您可以创建仅用于同步目的的特殊实体模型,将数据反序列化为这些对象,然后使用AutoMapper更新您的实体,例如:

更新

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

添加

dbUser = Mapper.Map<User>(apiUser);
db.client.Add(dbUser)
db.SaveChanges();
Run Code Online (Sandbox Code Playgroud)