仍然只是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文档中删除相应的屏幕权限? 如果是这样请提出查询或想法来做上述.. 提前谢谢..
答案 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();
}
}