如何使用ASP.NET Web API在DocumentDB中创建和更新文档之间的关系

我是.NET和Azure的新手,我正在尝试创建一个简单的Web API,以帮助我学习。 我有两个DocumentDB文档集合。 每个集合中的文件定义如下:

public class Log { [JsonProperty(PropertyName = "id")] public string Id { get; set; } [JsonProperty(PropertyName = "studentName")] public string StudentName { get; set; } [JsonProperty(PropertyName = "assignment")] public string Assignment { get; set; } [JsonProperty(PropertyName = "dueDate")] public DateTime DueDate { get; set; } [JsonProperty(PropertyName = "goal")] public string Goal { get; set; } [JsonProperty(PropertyName = "reflection")] public string Reflection { get; set; } [JsonProperty(PropertyName = "sessions")] public List Sessions { get; set; } } public class Session { [JsonProperty(PropertyName = "id")] public string Id { get; set; } [JsonProperty(PropertyName = "date")] public DateTime Date { get; set; } [JsonProperty(PropertyName = "duration")] public TimeSpan Duration { get; set; } [JsonProperty(PropertyName = "comment")] public string Comment { get; set; } } 

以下是我对日志文档的示例:

 { "id": "2", "studentName": "Joe student", "assignment": "Web APIs", "dueDate": "0001-01-01T00:00:00", "goal": "Keep mistakes to a minimum.", "reflection": "I'm getting there.", "sessions": [ ] } 

以下是我对Session文档的一个示例:

 { "id": "7", "date": "2015-04-26T00:00:00", "duration": "00:30:00", "comment": "Practiced for 30 minutes" } 

我想将Sessions与Logs联系起来,这样每个Log可能有几个会话,但每个会话都与一个Log以及一个Student相关。 我想我希望将会话作为单独的文档,因为我可能希望通过Student或Log获取Sessions列表。 还会有学生文件。 我正在努力将Sessions添加到日志中,而不是简单地在日志中复制会话。 我想得到这样的东西,它列出了相关会话的id:

 { "id": "2", "studentName": "Joe student", "assignment": "Web APIs", "dueDate": "0001-01-01T00:00:00", "goal": "Keep mistakes to a minimum.", "reflection": "I'm getting there.", "sessions": [1, 2, 7, 19, 22] } 

然后,我想通过将id替换为实际文档的内容来显示日志。

以下是一些相关的工作代码片段(不一定正确),以向您展示我的设计结构:

 public class PracticeLogRepository : DocumentDB { // ********** Logs section ********** // private PracticeSessionRepository _sessionsRepository; // specifies the database and document collection used by the repository public PracticeLogRepository() : base("Project3", "Logs") { } // Gets a list of practice Logs public Task<List> GetLogsAsync() { return Task<List>.Run(() => Client .CreateDocumentQuery(Collection.DocumentsLink) .ToList()); } // Gets the practice Log with the matching id public Task GetLogAsync(string id) { return Task.Run(() => Client .CreateDocumentQuery(Collection.DocumentsLink) .Where(pl => pl.Id == id) .AsEnumerable() .FirstOrDefault()); } 

 public class PracticeSessionRepository : DocumentDB { // ********** Session section ********** // // specifies the database and document collection used by the repository public PracticeSessionRepository() : base("Project3", "Sessions") { } // Gets a list of practice Sessions public Task<List> GetSessionsAsync() { return Task<List>.Run(() => Client .CreateDocumentQuery(Collection.DocumentsLink) .ToList()); } // Gets the practice Log with the matching id public Task GetSessionAsync(string id) { return Task.Run(() => Client .CreateDocumentQuery(Collection.DocumentsLink) .Where(pl => pl.Id == id) .AsEnumerable() .FirstOrDefault()); } 

 public class LogController : ApiController { private PracticeLogRepository _logsRepository; public LogController() { _logsRepository = new PracticeLogRepository(); } // GET: api/Log public async Task Get() { var logs = await _logsRepository.GetLogsAsync(); if (logs != null) return Ok(logs); return NotFound(); } // Get: api/Log/{id} public async Task Get(string id) { var log = await _logsRepository.GetLogAsync(id); if (log != null) return Ok(log); return NotFound(); } 

 public class SessionController : ApiController { private PracticeSessionRepository _sessionsRepository; public SessionController() { _sessionsRepository = new PracticeSessionRepository(); //_logsRepository = new PracticeLogRepository(); } // GET: api/Session public async Task Get() { var sessions = await _sessionsRepository.GetSessionsAsync(); if (sessions != null) return Ok(sessions); return NotFound(); } // Get: api/Session/{id} public async Task Get(string id) { var session = await _sessionsRepository.GetSessionAsync(id); if (session != null) return Ok(session); return NotFound(); } 

由于我自学,并且是非常新的.NET和C#,当然还有DocumentDB,我正在努力编写代码。 我真的很感激我应该如何创建日志文档的简单示例,以及如何通过添加会话来更新它。

如果您需要查看更多我的代码,请询问。 我只是不想让这复杂化。

我想确定我理解这个问题,这是对我的理解的回顾:

  • 日志和会话之间存在一对多的关系。

  • 您与Log和Student之间存在一对一的关系。

  • 您想通过学生或日志查询会话。

  • 您想从这些关系中填充数据(例如,获取会话数据)

请记住DocumentDB是一个NoSQL数据库,不支持文档间JOIN。

我建议您重新审视如何对数据建模 – 特别是如何表示关系(例如,是否将Sessions和Logs保存为单独的文档)。

以下文章详细介绍了建模数据: http : //azure.microsoft.com/en-us/documentation/articles/documentdb-modeling-data/

总结一下文章的要点 – 我会在规范化(例如将Sessions和Logs保持为单独的文档)和取消规范化(例如将Sessions和Logs保存在同一文档中)之间进行适当的权衡,给出应用程序的用例。 一般来说,当你有一个读取繁重的应用程序时,我更喜欢去标准化,当你有一个写入量大的应用程序时,我更喜欢标准化。

如果选择规范化 – 您只需发出后续请求即可获取日志的会话数据。 额外功劳 :您甚至可以更进一步,无需通过编写存储过程来发出多个网络请求。

如果您选择取消规范化,则只需查询整个文档,所有内容都将自动填充。 缺点是如果更新会话数据,可能必须扇出写入多个文档。