保持复杂对象树中的对象同步

时间:2014-06-20 20:43:26

标签: c# oop observer-pattern

说我有以下对象树。我的对象树并不是真正的愚蠢,但它确实有许多多对多的关系

Account
 - Users {UserId, Name, etc}
 - UserPermissions {User object, Permission object}
 - Permissions {PermissionId, Name, etc}

说,我想从Account对象下删除User或Permission对象。在任何一种情况下,我都希望包含已删除项目的任何UserPermission对象也从UserPermission集合中删除。

是否有一种优雅的方式,而无需手动删除UserPermission对象?我知道实体框架模型中的对象可以做到这一点,但不确定如何实现相同的结果......我没有使用EF,而是将对象结构保存到RavenDb。

根据请求,这是一个更全面的数据模型

public class Account
{
    public List<User> Users {get;set;}
    public List<UserGroup> UserGroups {get;set;}
    public List<Alert> Alerts {get;set;}
    public List<Resource> Resources {get;set;}
    public List<AlertSubscription> AlertSubscriptions {get;set;}
}
public class UserGroup : IAlertSubscriber
{
    public string Name {get;set;}
    public List<User> Users {get;set;}
}
public class User : IAlertSubscriber
{
    public string Name {get;set;}
}
public class AlertSubscription
{
    public Alert Alert {get;set;}
    public List<Resources> AlertPublishers {get;set;}
    public List<IAlertSubscribers> AlertTargets {get;set;}
    public int MinimumSeverity {get;set;}
}

所以,我希望能够做的是,如果我从Account.Users集合中删除用户,还可以从各种AlertTargets,UserGroups等中删除它。如果我从Account.UserGroups中删除UserGroup,我想要从AlertTargets中取消它,如果我从Account.Resources中删除一个资源,也从AlertSubsciptions中取出它...

1 个答案:

答案 0 :(得分:1)

我没有尝试同步两个相同数据的副本,而是使用单一副本。您可以只拥有UserPermissions列表,还可以计算另外两个集合:

public class Account
{
    private List<UserPermission> _userPersmission;

    public List<UserPermission> UserPermissions
    {
        get { return _userPersmission; }
        set { _userPersmission = value; }
    }

    public IEnumerable<User> Users
    {
        get { return _userPersmission.Select(up => up.User); }
    }

    public IEnumerable<Permission> Permissions
    {
        get { return _userPersmission.Select(up => up.Permission); }
    }
}

或根据其他两个集合计算UserPermissions。但我更喜欢以前的方法,因此UserPermission可以有额外的数据。

更新:如果您无法在不重复数据的情况下计算其中一些集合的所有集合,那么您将返回观察者。在您的情况下,主题是不同的集合,如用户。如果删除某些项目,主题应通知其他馆藏。 BindingList<T>是实施此类通知的主题。不幸的是,它没有提供有关删除了哪个项目的信息,因此您需要创建自定义绑定列表:

public class ExtendedBindingList<T> : BindingList<T>
{
    public T LastRemovedItem { get; private set; }

    protected override void RemoveItem(int index)
    {
        LastRemovedItem = base[index];
        base.RemoveItem(index);            
    }
}

您可以使用它来获取有关项目删除的通知:

public class Account
{
    public ExtendedBindingList<User> Users { get; private set; }

    public Account()
    {
        Users = new ExtendedBindingList<User>();
        Users.ListChanged += Users_ListChanged;
    }

    private void Users_ListChanged(object sender, ListChangedEventArgs e)
    {
        if (e.ListChangedType != ListChangedType.ItemDeleted)
            return;

        foreach (var group in UserGroups)
            group.Users.Remove(Users.LastRemovedItem);
    }

    // ...
 }

另一种选择是使用方法AddUserRemoveUser来修改用户列表。并将用户列表显示为IEnumerable

public class Account
{
    private List<User> _users = new List<User>();

    public IEnumerable<User> Users { get; }

    public void AddUser(User use)
    {
        _users.Add(user);
    }

    public void RemoveUser(User user)
    {
        _users.Remove(user);

        foreach (var group in UserGroups)
            group.Users.Remove(user);
    }

    // ...
 }