db4o Tranparent Persistence不会在我自己的ActivatableCollection <t> </t>中存储以后的对象

时间:2011-07-23 20:49:08

标签: db4o

我正在为db4o编写自己的ActivatableCollection<T>,但是在内置ActivatableList<T>实现中大量使用。我遇到了透明持久性似乎无法正常工作的问题。在下面的测试代码中:

[Fact]
void CanStoreActivatableCollection()
{
    var planets = new ActivatableCollection<Planet>();

    var pagingMemoryStorage = new PagingMemoryStorage();
    var config = Db4oEmbedded.NewConfiguration();
    config.Common.Add(new TransparentActivationSupport());
    config.Common.Add(new TransparentPersistenceSupport());
    config.File.Storage = pagingMemoryStorage;

    var objectContainer = Db4oEmbedded.OpenFile(config, "Memory.yap");

    planets.Add(new Planet("Mercury"));

    objectContainer.Store(planets);

    planets.Add(new Planet("Venus"));
    planets.Add(new Planet("Earth"));

    objectContainer.Commit();
    objectContainer.Close();

    config = Db4oEmbedded.NewConfiguration();
    config.Common.Add(new TransparentActivationSupport());
    config.Common.Add(new TransparentPersistenceSupport());
    config.File.Storage = pagingMemoryStorage;

    objectContainer = Db4oEmbedded.OpenFile(config, "Memory.yap");
    planets = objectContainer.Query<ActivatableCollection<Planet>>().FirstOrDefault();
    Assert.NotNull(planets);
    Assert.Equal(3, planets.Count);
    objectContainer.Close();
}

行星“水星”被储存,但不是“维纳斯”和“地球”。如果我从ActivatableCollection更改为ActivatableList,则存储所有3个行星。

我错过了什么?我的ActivatableCollection只是我能说的最好的ActivatableList实现。

以下是我对ActivatableCollection的实现:

public class ActivatableCollection<T>
    : ICollection<T>
    , IActivatable
    , INotifyCollectionChanged
{
    List<T> _list;

    List<T> List
    {
        get
        {
            if (_list == null)
                _list = new List<T>();
            return _list;
        }
    }

    public ActivatableCollection()
    {
    }

    public int Count
    {
        get
        {
            ActivateForRead();
            return List.Count;
        }
    }

    public bool IsReadOnly
    {
        get
        {
            ActivateForRead();
            return ((IList) List).IsReadOnly;
        }
    }

    public void Add(T t)
    {
        ActivateForWrite();
        List.Add(t);
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, t));
    }

    public void Clear()
    {
        ActivateForWrite();
        List.Clear();
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    public bool Contains(T t)
    {
        ActivateForRead();
        return List.Contains(t);
    }

    public void CopyTo(T[] array, int index)
    {
        ActivateForRead();
        List.CopyTo(array, index);
    }

    public IEnumerator<T> GetEnumerator()
    {
        ActivateForRead();
        return List.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public bool Remove(T t)
    {
        ActivateForWrite();
        bool removed = List.Remove(t);
        if (removed)
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, t));
        return removed;
    }

    [Transient]
    private IActivator _activator;

    public virtual void Bind(IActivator activator)
    {
        if (_activator == activator)
            return;
        if (activator != null && _activator != null)
            throw new InvalidOperationException();
        _activator = activator;
    }

    public virtual void Activate(ActivationPurpose purpose)
    {
        if (_activator == null)
            return;
        _activator.Activate(purpose);
    }

    protected virtual void ActivateForRead()
    {
        Activate(ActivationPurpose.Read);
    }

    protected virtual void ActivateForWrite()
    {
        Activate(ActivationPurpose.Write);
    }

    [Transient]
    public event NotifyCollectionChangedEventHandler CollectionChanged;

    protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (CollectionChanged != null)
            CollectionChanged(this, e);
    }
}

我还尝试从GenericTypeHandlerPredicate复制代码并注册我的ActivatableCollection以使用GenericCollectionTypeHandler。这导致GenericTypeFor()在存储“Mercury”时抛出InvalidOperationException()时崩溃。

1 个答案:

答案 0 :(得分:2)

对于有类似问题的人来说,也想在这里提一下db4o论坛的答案:

问题的第一部分: 从db4o的角度来看,'ActivatableCollection'对象中没有任何变化,因此不存储任何更改。这就是发生的事情:

  1. 添加项目时,ActivatableCollection标记为已更改。

  2. 提交时,存储更改。但是,'ActivatableCollection'保存对同一对象的引用。 db4o仅将更改存储在ActivatableCollection对象中,该对象是对List的引用。由于它是相同的,因此不存储实际的变化。

  3. 永远不会更新ActivatableCollection列表,因为它未标记为“已更改”

  4. 因此透明激活不会看到列表中的更改。您可以通过在ActivatableCollection实现中使用ActivatableList来解决您的问题。只需使用IList接口更改List并实例化ActivatableList而不是List。

    问题的第二部分:为什么即使在为此类型注册GenericCollectionTypeHandler时它也不起作用?这里我们点击了一个实现细节。 GenericCollectionTypeHandler具有受支持类型的内部列表,其中不包括自制的“ActivatableCollection”。 GenericCollectionTypeHandler实际上不是公共API的一部分,仅供内部使用。

    解决方法/修复

    只需使用ActivatableList<T>代替List<T>即可。然后一切正常。