【问题标题】:Database entities (models) required for Cosmos databaseCosmos 数据库所需的数据库实体(模型)
【发布时间】:2020-02-26 13:10:52
【问题描述】:

问题1:
之前我们使用的是WebApi+SqlServer,现在我们想迁移到WebApi+Cosmos DB。

早期实现(WebApi+SqlServer): 1. 我们创建了一个 Employee 模型,该模型将映射到来自 UI 的对象(此处为邮递员)
2. 稍后我们将在 WebApi 中对该模型进行验证。
3. 接下来,该模型将映射到 DatabaseEmployee(SQL server) 实体并插入到 SQL server。

新实现(WebApi+CosmosDB -SQL API+DocumentDB): 1. 上面的Step1和Step2也会在这里完成
2.这里是不是也需要创建一个DatabaseEmployee实体,或者直接向CosmosDB插入数据,不需要将Employee模型映射到DatabaseEmployee模型?

注意: 我认为:
a) 一对一映射:无需创建 CosmosDB 实体(DatabaseEmployee)。
b) 一对多映射:我们应该创建一个 CosmosDB 实体(DatabaseEmployee)。
c) 多对多映射:我们应该创建一个 CosmosDB 实体(DatabaseEmployee)。

问题 2:
对于一对多映射,请考虑以下示例 2 表 Employee 和 Department:
员工:EmpID、姓名、地址
部门:DeptID、DeptName、EmpId
在 SQL Server 中,我们有外键约束,因此我们可以维护 2 个表。
在 Cosmos DB 中,我们是否需要创建 2 个不同的容器,否则 1 个容器就足够了,如下所示?

{
DeptId:101,
DeptName: "XXX",
EmpData:
  {
     EmpId: 101,
     Empname:"AAA"
  },
 {
     EmpId: 102,
     Empname:"BBB"
 }
}

如果一个容器就足够了,那么我的 UI 模型必须如下:

Public class Department
{
  public int DeptId {get;set;}
  public string Deptname {get;set;}
  public List<Employee> EmpData {get;set;}
}

但我们有类似的模型:

public class Employee
{
 public int EmpId {get;set;}
 public string EmpName {get;set;}
}

public class Department
{ 
 public int DeptId {get;set;}
 public string DeptName {get;set;}
 public int EMpId {get;set;}  ** ForeignKey constraint as per SQL server **
}

注意:
如何在 WebApi 中维护模型以及如何创建类似于 CosmosDB 容器的数据库实体?

【问题讨论】:

  • 为什么要迁移到 CosmosDB?与 SQL Server 等传统关系数据库相比,CosmosDB 使用不同的数据库范例,例如,可能不适合将 Cosmos 用于 OLAP 工作负载。

标签: c# asp.net-mvc asp.net-web-api azure-cosmosdb azure-cosmosdb-sqlapi


【解决方案1】:

对于多对多关系,我们建议使用两个容器并使用 Change Feed 来保持它们之间的数据同步。但是,只有在为部门和员工进行大量读取和写入时,您才会这样做。在这里,部门实体几乎是静态的,员工变化频繁。所以这一切都取决于你如何访问数据,你应该尝试看看哪个是最有效的模型和分区键策略。

department 容器将使用 departmentId 作为分区键,并为每个员工提供一个新文档。我不会将员工嵌入到部门文档中,因为它可能会达到 2MB 的最大文档大小。此外,如果您经常更新部门,对员工进行少量更改,这将是昂贵的。

我会像这样在部门容器中建模数据。

{
    deptId:101,
    deptName: "XXX",
    type: "department"
}

{
     empId: 101,
     empName:"AAA",
     deptId: 101,
     type: "employee"
 }

要获取某个部门的所有员工,您可以编写这样的查询。

Select * FROM c WHERE c.deptId = 101

这将返回部门记录及其所有员工。在阅读代码中的结果集时,您检查“type”属性并反序列化为正确的类类型。

在员工方面,您会做相反的事情。您的分区键是employeeId,并且具有这样的模型。

{
     empId: 101,
     empName:"AAA",
     deptId: 101
}

部门 ID 的更新将仅在员工容器上完成。使用 Change Feed,您可以监听更改,然后在部门容器上执行 upsert 以使它们保持同步(这就是您在 NoSQL 数据库中执行引用完整性的方式)。

关于如何在 Cosmos DB 中对数据进行建模和分区,有很多很棒的文档。我一定会阅读这些以了解如何为 Cosmos 进行最佳设计。

Model data

Partition data

Real world example

希望这会有所帮助。

【讨论】:

  • Change Feed 监听器是否有可能错过消息或以其他方式失败?使用 Change Feed 侦听器实现参照完整性时,数据库状态是否有任何保证?
  • 是的,您应该在异常处理程序中实现死信队列,然后通过另一个进程处理以重试处理。如果您正在积极收听和处理更改源,您将不会错过更改,但是,如果您的间隔非常长,您将只能看到项目的最新更新。 Change Feed 不是真正的 oplog,它只存储项目的最新版本。通常,对于大多数情况,这很好,因为目的是使两个容器保持同步。
猜你喜欢
  • 2017-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-23
  • 1970-01-01
  • 1970-01-01
  • 2014-04-16
相关资源
最近更新 更多