微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

数据建模 – 如何在面向文档的数据库系统(如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仅显示特定任务的任务.

为了在文档数据库中进行建模,我想到了以下三点:

>模型任务作为单独的文档.这似乎是一种反文档数据库,因为大多数时候你看一个公司或联系人,你会想看到任务列表,因此必须执行很多文档的连接.
>保留与公司联系人不相关的任务.打开列表,并将每个联系人的列表中的联系人的任务放在列表中.不幸的是,如果您想查看公司的所有任务(这可能会很多),则必须将公司的所有任务与每个联系人的所有任务相结合.当您要将联系人的任务与联系人分离时,我也看到这一点很复杂,因为您必须将其从联系人转移到公司
>将所有任务保留在Company.Tasks列表中,并且每个联系人都有与其关联的任务的id值列表.这似乎是一个很好的方法,除了必须手动获取id值,并且必须为联系人制作任务实体的子列表.

在面向文档的数据库中建模这种数据的建议方法是什么?

解决方法

使用非规范化参考:

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作为自己的文档进行建模.使用上述方法使这很简单.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


SELECT a.*,b.dp_name,c.pa_name,fm_name=(CASE WHEN a.fm_no=&#39;LJCG001H&#39; THEN dbo.ELTPNAME(a.fw_nu) ELSE d.fm_name END),e.fw_state_nm,f.fw_rmk_nm
if not exists(select name from syscolumns where name=&#39;tod_no&#39; and id=object_id(&#39;iebo09d12&#39;)) alter table iebo09d12 add tod_no varchar(
select a.*,pano=a.pa_no,b.pa_name,f.dp_name,e.fw_state_nm,g.fa_name from LJSS007H a (nolock) Left join LJPA002H b (nolock) On a.pa_no =b.pa_no Left jo
要在 SQL Server 2019 中设置定时自动重启,可以使用 Windows 任务计划程序。下面是详细的步骤: 步骤一:创建批处理文件 打开记事本。 输入以下内容: net stop &quot;SQL Server (MSSQLSERVER)&quot; net start &quot;SQ
您收到的错误消息表明数据库 &#39;EastRiver&#39; 的事务日志已满,导致数据库操作失败。要解决这个问题,可以按照以下步骤操作: 1. 备份事务日志首先,备份事务日志以释放空间: BACKUP LOG [EastRiver] TO DISK = N&#39;C:\Backup\East
首先我需要查询出需要使用SQL Server Profiler跟踪的数据库标识ID,若不知道怎么查询数据库的标识ID, 打开SQL Server management studio,点击工具。选择SQL Server Profiler。 登录,登录成功后,如果有个默认弹窗,先取消 新建追踪 命名
--最新的解决方法 --先创建用户帐户,不进行授权,然后通过下面的SQL语句将该用户帐户关联至对应的数据库用户。优点是避免了重新授权的操作。 USE tempdbEXEC sp_change_users_login &#39;Update_One&#39;, &#39;iemis&#39;, &#3
命令: ALTER TABLE 表名 add 列名 数据类型 default 默认值 not null 例如: ALTER TABLE LJEL005H add el_req int default 15 not null
declare @i int set @i=340 while @i&lt;415 begin set @i=@iʱ insert into LJWK007H select &#39;2024&#39;,&#39;28&#39;,&#39;9110&#39;,&#39;3PTSD621000000