是否可以在ravendb中删除级联

时间:2012-12-11 15:01:54

标签: c# ravendb

仍然只是ravendb的首发。我怀疑raven db是否支持某种参照完整性。

这是我的疑问和工作..

我的文档类型屏幕如下

public class Screens 
    {
        public String Id { get; set; }
        public String ScreenName { get; set; }
}

另一个名为RightsDeclaration的文件如下

public class RightsDeclaration 
    {
        public RightsDeclaration()
        {
            _screenrights = new List<ScreenRight>();
        }

        public String Id { get; set; }// Role Name 
        List<ScreenRight> _screenrights;
        public List<ScreenRight> ScreenRights { get { return _screenrights; } set { _screenrights = value; } }
}

现在屏幕权限类如下所示,屏幕名称字段如下所示

public class ScreenRight :
    {

        public String ScreenName { get; set; }
        public Boolean Create { get; set; }
        public Boolean Read { get; set; }
        public Boolean Update { get; set; }
        public Boolean Delete { get; set; }
        public Boolean Approve { get; set; }
        public Boolean Access { get; set; }
        public Boolean Print { get; set; }
        public Boolean Email { get; set; }
}

现在我首先创建一些屏幕列表,然后为每个角色分配权限 提到什么是屏幕名称和权利列表。到目前为止,一切都很顺利。现在,如果我将删除屏幕类中的屏幕名称,但随后该权限声明中仍然存在该屏幕的屏幕权限。是否可以从userrights文档中删除相应的屏幕权限? 如果是这样请提出查询或想法来做上述.. 提前谢谢..

1 个答案:

答案 0 :(得分:3)

Raven不支持真正的引用完整性,这不是文档数据库通常感兴趣的东西。但是,您可以达到同样的效果。

首先,我不会通过名称引用,屏幕ID是更好的密钥,因为您可以通过它加载。如果您还想在ScreenRight课程中捕捉屏幕名称,那很好,但这是次要问题。

此外,还有一件小事,但请尽量保持您的实体/文档名称不变。 Screen代替Screens。它将为您节省一些麻烦。

处理删除的一种方法是在删除主数据库时专门更新引用文档。如果您在同一会话中执行此操作,则会有事务保证。您必须考虑查询结果的分页。

using (var session = documentStore.OpenSession())
{
    var screen = session.Load<Screen>(screenId);
    if (screen != null)
    {
        // Set up some variables to help with pagination.
        var now = DateTime.UtcNow;
        const int pageSize = 1024;
        var page = 0;

        while (true)
        {
            // Get all rights that use this screen.
            // Waiting for nonstale results is appropriate, but we want the same "now" with each page.
            var rights = session.Query<RightsDeclaration>()
                                .Customize(x => x.WaitForNonStaleResultsAsOf(now))
                                .Where(x => x.ScreenRights.Any(y => y.ScreenId == screenId))
                                .Skip(page * pageSize)
                                .Take(pageSize)
                                .ToList();

            foreach (var right in rights)
            {
                // Remove the screen from any rights that used it
                right.ScreenRights.RemoveAll(x => x.ScreenId == screenId);

                // You might want to delete any empty rights declarations
                if (right.ScreenRights.Count == 0)
                    session.Delete(right);
            }

            // Exit when we get back less than a full page, indicating there are no more pages.
            if (rights.Count < pageSize)
                break;

            // Next page please.
            page++;
        }

        // Delete the screen.
        session.Delete(screen);

        // Save all your changes together.
        session.SaveChanges();
    }
}

另一种方法是使用Raven的Patching API来执行更新。它更快,但您没有交易保证。

您还可以查看Raven的Cascading Deletes Bundle,但我不认为它会在这里工作,因为您不一定每次都删除RightsDeclaration

<强>更新

我将一些较难的分页代码推送到一个易于使用的扩展方法中。现在这是ravendb/contrib项目的一部分。使用这些扩展,您的代码更简单:

using (var session = documentStore.OpenSession())
{
    var screen = session.Load<Screen>(screenId);
    if (screen != null)
    {
        // Get all rights that use this screen.
        session.Query<RightsDeclaration>()
                .Customize(x => x.WaitForNonStaleResultsAsOfNow())
                .Where(x => x.ScreenRights.Any(y => y.ScreenId == screenId))
                .ForEachWithPaging(right =>
                    {
                        // Remove the screen from any rights that used it
                        right.ScreenRights.RemoveAll(x => x.ScreenId == screenId);

                        // You might want to delete any empty rights declarations
                        if (right.ScreenRights.Count == 0)
                            session.Delete(right);
                    });

        // Delete the screen.
        session.Delete(screen);

        // Save all your changes together.
        session.SaveChanges();
    }
}