数据建模 – 如何在面向文档的数据库系统(如RavenDB)中建立与父
面向文档的数据库(特别是RavenDB)真的很有趣,我想和他们玩一下.然而,作为非常习惯于关系映射的人,我试图想到如何在文档数据库中正确建模数据.
说我在我的C#应用??程序中拥有以下实体的CRM(不需要的属性): public class Company { public int Id { get; set; } public IList<Contact> Contacts { get; set; } public IList<Task> Tasks { get; set; } } public class Contact { public int Id { get; set; } public Company Company { get; set; } public IList<Task> Tasks { get; set; } } public class Task { public int Id { get; set; } public Company Company { get; set; } public Contact Contact { get; set; } } 我正在考虑将这一切都放在公司文件中,因为联系人和任务没有公司的目的,大多数时候查询任务或联系人也将显示有关联系公司的信息. 问题来自Task实体.说业务要求任务总是与公司相关联,但也可以与任务相关联. 在关系模型中,这很简单,因为您只需要一个“任务”表,并将Company.Task与公司的所有任务相关联,而Contact.Tasks仅显示特定任务的任务. 为了在文档数据库中进行建模,我想到了以下三点: >模型任务作为单独的文档.这似乎是一种反文档数据库,因为大多数时候你看一个公司或联系人,你会想看到任务列表,因此必须执行很多文档的连接. 在面向文档的数据库中建模这种数据的建议方法是什么? 解决方法使用非规范化参考:http://ravendb.net/faq/denormalized-references 实质上你有一个DenormalizedReference类: public class DenormalizedReference<T> where T : INamedDocument { public string Id { get; set; } public string Name { get; set; } public static implicit operator DenormalizedReference<T> (T doc) { return new DenormalizedReference<T> { Id = doc.Id,Name = doc.Name } } } 您的文档看起来像 – 我已经实现了INamedDocument接口 – 这可以是你需要的任何东西: public class Company : INamedDocument { public string Name{get;set;} public int Id { get; set; } public IList<DenormalizedReference<Contact>> Contacts { get; set; } public IList<DenormalizedReference<Task>> Tasks { get; set; } } public class Contact : INamedDocument { public string Name{get;set;} public int Id { get; set; } public DenormalizedReference<Company> Company { get; set; } public IList<DenormalizedReference<Task>> Tasks { get; set; } } public class Task : INamedDocument { public string Name{get;set;} public int Id { get; set; } public DenormalizedReference<Company> Company { get; set; } public DenormalizedReference<Contact> Contact { get; set; } } 现在保存任务的工作原理与以前一样: var task = new Task{ Company = myCompany,Contact = myContact }; 然而,将所有这一切拉回来将意味着您只需要获得子对象的非规范化引用.为了水合这些我使用一个索引: public class Tasks_Hydrated : AbstractIndexCreationTask<Task> { public Tasks_Hydrated() { Map = docs => from doc in docs select new { doc.Name }; TransformResults = (db,docs) => from doc in docs let Company = db.Load<Company>(doc.Company.Id) let Contact = db.Load<Contact>(doc.Contact.Id) select new { Contact,Company,doc.Id,doc.Name }; } } 并使用您的索引来检索水合任务是: var tasks = from c in _session.Query<Projections.Task,Tasks_Hydrated>() where c.Name == "taskmaster" select c; 我觉得很干净:) 作为设计对话 – 一般规则是,如果您需要单独加载子文档,而不是父文档的一部分.无论是编辑还是查看 – 您应该使用自己的Id作为自己的文档进行建模.使用上述方法使这很简单. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |