我正在为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()时崩溃。
答案 0 :(得分:2)
对于有类似问题的人来说,也想在这里提一下db4o论坛的答案:
问题的第一部分: 从db4o的角度来看,'ActivatableCollection'对象中没有任何变化,因此不存储任何更改。这就是发生的事情:
添加项目时,ActivatableCollection标记为已更改。
提交时,存储更改。但是,'ActivatableCollection'保存对同一对象的引用。 db4o仅将更改存储在ActivatableCollection对象中,该对象是对List的引用。由于它是相同的,因此不存储实际的变化。
永远不会更新ActivatableCollection列表,因为它未标记为“已更改”
因此透明激活不会看到列表中的更改。您可以通过在ActivatableCollection实现中使用ActivatableList来解决您的问题。只需使用IList接口更改List并实例化ActivatableList而不是List。
问题的第二部分:为什么即使在为此类型注册GenericCollectionTypeHandler时它也不起作用?这里我们点击了一个实现细节。 GenericCollectionTypeHandler具有受支持类型的内部列表,其中不包括自制的“ActivatableCollection”。 GenericCollectionTypeHandler实际上不是公共API的一部分,仅供内部使用。
只需使用ActivatableList<T>
代替List<T>
即可。然后一切正常。