方案:
我有两个MySQL数据库:
表格示例:
大数据库用户:
文字使用者名称
客户端数据库用户
问题:
我需要同步数据库,但是我不知道如何以最佳方式做到这一点。我读过this question,但是它已经很老了,不能涵盖我的情况。
我通过REST API与主数据库进行通信,因此不能选择直接连接。
我的同步算法
公共(public)类ApiUser {
int id;
字符串登录;
字符串密码;
}
公共(public)类用户{
int id;
int api_id;
字符串登录;
字符串密码;
}
我的代码:
公共(public)无效syncUsers(列表 ApiUsers)
{
使用(var db = new dbEntities())
{
ApiUsers.ForEach(apiUser =>
{
var dbUser = db.client
哪里(c => c.api_id == apiUser.id)
.SingleOrDefault();
如果(dbUser == null)
{
var userObj =新的user()
{
api_id = apiUser.id,
登录= apiUser.login,
密码= apiUser.password
};
db.client.Add(userObj);
}
别的
{
dbUser.api_id = apiUser.id,
dbUser.login = apiUser.login,
dbUser.password = apiUser.password
}
});
db.SaveChanges();
}
}
问题:
如何做得更好?我在从主数据库中删除实体时遇到问题,我的算法没有涵盖这种情况。
最佳答案
我假设所有用户的交互或自动事务都仅在master数据库中完成(否则,您将需要某种合并复制,这并非易事)。
至于已删除的实体,有几个选项。无论如何,您的主数据库必须将有关已删除实体的信息传播到客户端数据库。
1.每个实体(如果已删除)都保留该信息。
在这种情况下,您可以使用软删除选项,该选项可以通过覆盖DbContext的OnModelCreating和SaveChanges方法在EF中轻松实现(您可以在网上找到很多代码示例,其中包含实现)。
此选项也有一些缺点-您可能拥有一个非常复杂的域模型,其中包含实体之间的关系,因此在删除其父实体时,必须小心地软删除子实体。如果您对主数据库和客户端数据库有不同的前端应用程序,则必须将它们全部升级,以使新的软删除属性(例如IsDeleted)生效。但是,在这种情况下,(软)已删除实体的同步本身非常简单,因为它只需要在客户端更新一个附加属性。
2.删除实体的新表。
在这种情况下,您必须为每个实体创建一个附加表,并在删除任何实体之前插入ID值。您必须重写DbContext的SaveChanges才能拦截处于EntityState.Deleted状态的实体。
关于第一个问题,这取决于您要增强的功能。如果您希望表中有许多记录,则应考虑引入其他字段以仅更新那些在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();