// This file is part of the Ubik project
// Copyright (c) 2006 Nicholas Blumhardt <nicholas.blumhardt@gmail.com>
//
// This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
using System;
using System.Collections.Generic;
using System.Text;
namespace Ubik.Engine.Client{
/// <summary>
/// A virtual collection is used when the convenience of a collection member on the Individual's
/// interface is handy but the overhead of serialising the relationship with the object is too great.
/// VirtualCollection uses a query to retrieve the relationship each time it is requested.
/// VirtualCollection represents a one-to-many relationship where the type on the 'many' side (i.e. the
/// one that references a single object) 'owns' the relationship.
/// Note that the implementation of Count currently does a very expensive roundtrip, so if performance
/// is an issue, enumerate the collection and count that way.
/// </summary>
/// <typeparam name="T"></typeparam>
public class VirtualCollection<T> : ICollection<T> where T : Individual
{
Individual _parent;
string _referencedProperty;
VirtualCollectionMultiplicity _multiplicity;
/// <summary>
/// Construct a virtual collection that will return Individuals where the value
/// of the property named <paramref name="referencedProperty"/> equals the parent
/// object.
/// </summary>
/// <param name="parent">The Individual to which this dynamic collection belongs.</param>
/// <param name="referencedProperty">The property on the referenced object that
/// identifies it as belonging to this collection.</param>
/// <param name="multiplicity">Indicates the way that the referenced property relates back to this individual.
/// I.e. if the referenced property is single-valued (a reference) then use OneToMany, otherwise if it is
/// a collection, use ManyToMany.</param>
public VirtualCollection(Individual parent, string referencedProperty, VirtualCollectionMultiplicity multiplicity)
{
if (parent == null)
throw new ArgumentNullException("parent");
if (referencedProperty == null)
throw new ArgumentNullException("referencedProperty");
_parent = parent;
_referencedProperty = referencedProperty;
_multiplicity = multiplicity;
}
#region IEnumerable<T> Members
/// <summary>
/// See <see cref="IEnumerable<T>"/>
/// </summary>
/// <returns></returns>
public IEnumerator<T> GetEnumerator()
{
foreach (T t in GetItems())
yield return t;
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
private List<T> GetItems()
{
return _parent.Session.Select<T>(Test);
}
/// <summary>
/// This is calculated on-the-fly rather than during construction because
/// at that point the object may not yet have obtained its Identity (during deserialisation)
/// </summary>
private string Test
{
get
{
if (_multiplicity == VirtualCollectionMultiplicity.OneToMany)
{
return string.Format("{0}={{{1}}}", _referencedProperty, _parent);
}
else
{
return string.Format("{0}[Identity={{{1}}}]", _referencedProperty, _parent);
}
}
}
#region ICollection<T> Members
/// <summary>
/// See <see cref="ICollection<T>"/>.
/// </summary>
public int Count
{
get
{
return GetItems().Count;
}
}
/// <summary>
/// See <see cref="ICollection<T>"/>.
/// </summary>
public object SyncRoot
{
get
{
return this;
}
}
/// <summary>
/// See <see cref="ICollection<T>"/>.
/// </summary>
public bool IsSynchronised
{
get
{
return false;
}
}
/// <summary>
/// Not implemented.
/// See <see cref="ICollection<T>"/>.
/// </summary>
public void Add(T item)
{
throw new NotImplementedException(VirtualCollectionResources.CollectionIsReadOnly);
}
/// <summary>
/// Not implemented.
/// See <see cref="ICollection<T>"/>.
/// </summary>
public void Clear()
{
throw new NotImplementedException(VirtualCollectionResources.CollectionIsReadOnly);
}
/// <summary>
/// Not implemented.
/// See <see cref="ICollection<T>"/>.
/// </summary>
public bool Contains(T item)
{
return _parent.Session.Select<T>(Test + " && Identity = {" + item.ToString() + "}").Count > 0;
}
/// <summary>
/// Not implemented.
/// See <see cref="ICollection<T>"/>.
/// </summary>
public void CopyTo(T[] array, int arrayIndex)
{
throw new NotImplementedException(VirtualCollectionResources.CollectionIsReadOnly);
}
/// <summary>
/// Not implemented.
/// See <see cref="ICollection<T>"/>.
/// </summary>
public bool IsReadOnly
{
get
{
return true;
}
}
/// <summary>
/// Not implemented.
/// See <see cref="ICollection<T>"/>.
/// </summary>
public bool Remove(T item)
{
throw new NotImplementedException(VirtualCollectionResources.CollectionIsReadOnly);
}
#endregion
}
}
|