简体   繁体   English

C# WPF Entity Framework 6 同步数据库

[英]C# WPF Entity Framework 6 Synchronization databases

Scenario:设想:

I have two MySQL databases:我有两个 MySQL 数据库:

  1. Big master database大主数据库
  2. Small client database小客户数据库

Example tables:示例表:

Big Database User:大数据库用户:

text username文本用户名

  • int id内部标识
  • varchar login登录
  • varchar password varchar 密码
  • ... a lot more fields ...更多领域

Client Database User客户端数据库用户

  • int id内部标识
  • int UNIQUE api_id (id from master) int UNIQUE api_id (id from master)
  • varchar login登录
  • varchar password varchar 密码

Problem: I need to synchronize databases, but i don't know how to do that in the best way.问题:我需要同步数据库,但我不知道如何以最好的方式做到这一点。 I read this question , but it's quite old, and not cover my case.我读过这个问题,但它已经很老了,并没有涵盖我的情况。 I communicate with master database via REST API, direct connection is not the option.我通过 REST API 与主数据库通信,直接连接不是选项。

My synchronization Algorithm我的同步算法

  • Download and deserialize data from REST API ( for example /api/users/ ) to List of ApiUser objects将数据从 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; 
    }
  • Iterate over List of Apiusers迭代Apiusers列表
    • If entity with ApiUser.id exist overwrite all fields如果存在带有 ApiUser.id 的实体,则覆盖所有字段
    • Else create new entity否则创建新实体
  • Save changes保存更改

My code:我的代码:

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

Question: How to do it better?问题:如何做得更好? I have problem with deleted entities from master database, my algorithm does not cover cover this case.我有从主数据库中删除实体的问题,我的算法不涵盖这种情况。

I assume that all user's interaction or automated transactions are done only in the master database (otherwise you would need some kind of merge replication, which is not trivial).我假设所有用户的交互或自动事务仅在主数据库中完成(否则您将需要某种合并复制,这不是微不足道的)。

As for deleted entities, there are several options.对于已删除的实体,有多种选择。 In any case, your master database must propagate information about deleted entities to the client databases.在任何情况下,您的主数据库都必须将有关已删除实体的信息传播到客户端数据库。

1. Each entity holds the information if it's deleted. 1. 如果信息被删除,每个实体都持有该信息。

In this case, you can use soft delete option which can be easily implemented within EF by overriding the DbContext's OnModelCreating and SaveChanges methods (you can find many code samples with the implementation on the net).在这种情况下,您可以使用软删除选项,该选项可以通过覆盖 DbContext 的 OnModelCreating 和 SaveChanges 方法在 EF 中轻松实现(您可以在网上找到许多带有实现的代码示例)。 This option has some drawbacks, too - you probably have quite complex domain model with relations between entities so you have to take care of soft deleting child entities when you delete their parent.此选项也有一些缺点 - 您可能有非常复杂的域模型,其中包含实体之间的关系,因此您必须在删除其父实体时处理软删除子实体。 If you have different front-end applications for master database and for the client databases you'll have to upgrade all of them to take new soft delete property (eg IsDeleted) into action.如果您有不同的前端应用程序用于主数据库和客户端数据库,您将必须升级所有这些应用程序以将新的软删除属性(例如 IsDeleted)付诸实施。 But the synchronization itself for the (soft) deleted entities is in this case very simple as it takes only one additional property to be updated at client's side.但是在这种情况下,(软)删除实体的同步本身非常简单,因为它只需要在客户端更新一个附加属性。

2. New tables for deleted entities. 2. 删除实体的新表。

In this case, you'll have to create an additional table for each entity and insert Id value before you delete any entity.在这种情况下,您必须为每个实体创建一个附加表并在删除任何实体之前插入 Id 值。 You'll have to override DbContext's SaveChanges to intercept entities in the EntityState.Deleted state.您必须覆盖 DbContext 的 SaveChanges 以拦截 EntityState.Deleted 状态中的实体。


Regarding the first question it depends what you want to enhance.关于第一个问题,这取决于您想增强什么。 If you expect to have many records in tables you should think about introducing additional field to update only those records which were really updated at the master database - you can chose between int (entity version), DateTime, or guid value, respectively, depending what is the most suitable for your case.如果您希望表中有许多记录,您应该考虑引入额外的字段来仅更新那些在主数据库中真正更新的记录 - 您可以分别在 int(实体版本)、DateTime 或 guid 值之间进行选择,具体取决于什么最适合您的情况。

If you want to separate the concern of dealing with property-by-property updating you can create special entity models only for the sync purposes, deserialize your data to those objects and then use AutoMapper for updating your entites, for example:如果您想单独处理逐个属性更新的问题,您可以仅为同步目的创建特殊的实体模型,将您的数据反序列化为这些对象,然后使用AutoMapper更新您的实体,例如:

UPDATE更新

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

ADD添加

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM