3

仍然只是 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; }
}

现在首先我将创建一些屏幕列表,然后我为每个角色分配权限,并提及屏幕名称和权限列表。到目前为止,一切都很好。现在在一个场景中,如果我要删除屏幕类中的屏幕名称,但该屏幕的屏幕权限仍然存在于权限声明中。是否也可以从用户权限文档中删除相应的屏幕权限?如果是这样,请提及执行上述操作的查询或想法..提前致谢..

4

1 回答 1

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();
    }
}
于 2012-12-11T16:11:47.580 回答