// ========================================================
namespace Kerosene.ORM.Maps
{
using Kerosene.Tools;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
// ====================================================
/// <summary>
/// Represents a column in the database that will be transfered back and forth the record associated with the
/// entities even if there is no matching member in the type for the column name. This class is typically used to
/// retrieve and persist the columns used by the extended members collection of the map.
/// </summary>
public class KMapForcedColumn<T> : IKMapForcedColumn where T : class
{
KMetaMap<T> _MetaMap = null;
string _Name = null;
Action<T, object> _LoadEntityDelegate = null;
Func<T, object> _WriteRecordDelegate = null;
internal KMapForcedColumn(KMetaMap<T> map, string name)
{
_MetaMap = map;
_Name = name;
}
internal void OnDispose()
{
_MetaMap = null;
_LoadEntityDelegate = null;
_WriteRecordDelegate = null;
}
internal KMapForcedColumn<T> OnClone(KMetaMap<T> newmap)
{
var cloned = new KMapForcedColumn<T>(newmap, _Name);
cloned._LoadEntityDelegate = _LoadEntityDelegate;
cloned._WriteRecordDelegate = _WriteRecordDelegate;
return cloned;
}
/// <summary>
/// The map this instance belongs to.
/// </summary>
public KMetaMap<T> MetaMap
{
get { return _MetaMap; }
}
IKMetaMap IKMapForcedColumn.MetaMap
{
get { return this.MetaMap; }
}
/// <summary>
/// The name of the forced column in the database.
/// </summary>
public string Name
{
get { return _Name; }
}
/// <summary>
/// Returns the string representation of this instance.
/// </summary>
public override string ToString()
{
StringBuilder sb = new StringBuilder();
if (_MetaMap == null) sb.Append("disposed::[");
sb.Append(_Name ?? "-");
if (_MetaMap == null) sb.Append("]");
return sb.ToString();
}
/// <summary>
/// If not null the delegate to invoke with (entity, value) arguments, typically to load into the entity the
/// value obtained from the record associated with this column. If this delegate is null, the value is loaded
/// into the record only if there is a matching member in the type, otherwise no transfer is performed.
/// </summary>
public Action<T, object> LoadEntityDelegate
{
get { return _LoadEntityDelegate; }
}
Action<object, object> IKMapForcedColumn.LoadEntityDelegate
{
get
{
if (_LoadEntityDelegate == null) return null;
Action<object, object> temp = (entity, value) => { _LoadEntityDelegate((T)entity, value); };
return temp;
}
}
/// <summary>
/// Sets or clears the delegate to invoke with (entity, value) arguments, typically to load into the entity
/// the value obtained from the record associated with this column. If this delegate is null, the value is
/// loaded into the record only if there is a matching member in the type, otherwise no transfer is performed.
/// <para>This method fails if the map is already validated.</para>
/// <para>Returns this instance to permit a fluent syntax chaining.</para>
/// </summary>
/// <param name="onLoad">The delegate to set or null to clear it.</param>
public KMapForcedColumn<T> OnLoadEntity(Action<T, object> onLoad)
{
if (_MetaMap == null) throw new ObjectDisposedException(this.ToString());
if (_MetaMap.IsDisposed) throw new ObjectDisposedException(_MetaMap.ToString());
if (_MetaMap.IsValidated) throw new InvalidOperationException(string.Format("Map '{0}' is already validated.", _MetaMap));
_LoadEntityDelegate = onLoad;
return this;
}
IKMapForcedColumn IKMapForcedColumn.OnLoadEntity(Action<object, object> onLoad)
{
return this.OnLoadEntity(onLoad);
}
/// <summary>
/// If not null the delegate to invoke with (entity) argument to obtain the value associated with this column
/// that will be written into the record. If this delegate is null then a value is obtained from the entity
/// only if there is a matching member in the type, otherwise no transfer is performed.
/// </summary>
public Func<T, object> WriteRecordDelegate
{
get { return _WriteRecordDelegate; }
}
Func<object, object> IKMapForcedColumn.WriteRecordDelegate
{
get
{
if (_WriteRecordDelegate == null) return null;
Func<object, object> temp = (entity) => { return _WriteRecordDelegate((T)entity); };
return temp;
}
}
/// <summary>
/// Sets or clears the delegate to invoke with (entity) argument to obtain the value associated with this
/// column that will be written into the record. If this delegate is null then a value is obtained from the
/// entity only if there is a matching member in the type, otherwise no transfer is performed.
/// <para>This method fails if the map is already validated.</para>
/// <para>Returns this instance to permit a fluent syntax chaining.</para>
/// </summary>
/// <param name="onWrite">The delegate to set or null to clear it.</param>
public KMapForcedColumn<T> OnWriteRecord(Func<T, object> onWrite)
{
if (_MetaMap == null) throw new ObjectDisposedException(this.ToString());
if (_MetaMap.IsDisposed) throw new ObjectDisposedException(_MetaMap.ToString());
if (_MetaMap.IsValidated) throw new InvalidOperationException(string.Format("Map '{0}' is already validated.", _MetaMap));
_WriteRecordDelegate = onWrite;
return this;
}
IKMapForcedColumn IKMapForcedColumn.OnWriteRecord(Func<object, object> onWrite)
{
return this.OnWriteRecord(onWrite);
}
}
// ====================================================
/// <summary>
/// Represents the collection of columns in the database that will be transfered back and forth the record
/// associated with the entities even if there are no matching member in the type for the column names. This
/// class is typically used to retrieve and persist the columns used by the extended members collection of the
/// map.
/// </summary>
public class KMapForcedColumnCollection<T> : IKMapForcedColumnCollection where T : class
{
KMetaMap<T> _MetaMap = null;
List<KMapForcedColumn<T>> _List = new List<KMapForcedColumn<T>>();
internal KMapForcedColumnCollection(KMetaMap<T> map)
{
_MetaMap = map;
}
internal void OnDispose()
{
foreach (var entry in _List) entry.OnDispose(); _List.Clear();
_MetaMap = null;
}
internal KMapForcedColumnCollection<T> OnClone(KMetaMap<T> newmap)
{
var cloned = new KMapForcedColumnCollection<T>(newmap);
foreach (var entry in _List) cloned._List.Add(entry.OnClone(newmap));
return cloned;
}
/// <summary>
/// Returns the string representation of this instance.
/// </summary>
public override string ToString()
{
StringBuilder sb = new StringBuilder();
if (_MetaMap == null) sb.Append("disposed::[");
if (Count == 0) sb.Append("-");
else
{
bool first = true; foreach (var entry in _List)
{
if (first) first = false; else sb.Append(", ");
sb.Append(entry);
}
}
if (_MetaMap == null) sb.Append("]");
return sb.ToString();
}
/// <summary>
/// The map this instance belongs to.
/// </summary>
public KMetaMap<T> MetaMap
{
get { return _MetaMap; }
}
IKMetaMap IKMapForcedColumnCollection.MetaMap
{
get { return this.MetaMap; }
}
/// <summary>
/// Adds a new entry into this collection.
/// <para>Returns the new entry that has been created to permit a fluent syntax chaining.</para>
/// <para>This method fails if the map is already validated.</para>
/// </summary>
/// <param name="name">A dynamic lambda expression resolving into the name of the forced column.</param>
public KMapForcedColumn<T> Add(Func<dynamic, object> name)
{
if (_MetaMap == null) throw new ObjectDisposedException(this.ToString());
if (_MetaMap.IsDisposed) throw new ObjectDisposedException(_MetaMap.ToString());
if (_MetaMap.IsValidated) throw new InvalidOperationException(string.Format("Map '{0}' is already validated.", _MetaMap));
if (name == null) throw new ArgumentNullException("name", "Specification cannot be null.");
var str = _MetaMap.MetaLink.Link.Parser.Parse(name);
str = str.Validated("Name");
var entry = _List.Find(x => x.Name == str);
if (entry != null) throw new DuplicateException(string.Format(
"Column '{0}' already registered in map '{1}'", str, _MetaMap));
entry = new KMapForcedColumn<T>(_MetaMap, str); _List.Add(entry);
return entry;
}
IKMapForcedColumn IKMapForcedColumnCollection.Add(Func<dynamic, object> name)
{
return this.Add(name);
}
/// <summary>
/// Removes the given entry from this collection. Returns true if the entry has been removed sucessfully or
/// false otherwise.
/// </summary>
/// <param name="entry">The entry to remove from this collection.</param>
public bool Remove(KMapForcedColumn<T> entry)
{
if (_MetaMap == null) throw new ObjectDisposedException(this.ToString());
if (_MetaMap.IsDisposed) throw new ObjectDisposedException(_MetaMap.ToString());
if (_MetaMap.IsValidated) throw new InvalidOperationException(string.Format("Map '{0}' is already validated.", _MetaMap));
if (entry == null) throw new ArgumentNullException("entry", "Entry cannot be null.");
bool r = _List.Remove(entry); if (r) entry.OnDispose();
return r;
}
bool IKMapForcedColumnCollection.Remove(IKMapForcedColumn entry)
{
return this.Remove((KMapForcedColumn<T>)entry);
}
/// <summary>
/// Gets the number of entries in this collection.
/// </summary>
public int Count
{
get { return _List == null ? 0 : _List.Count; }
}
/// <summary>
/// Returns the first entry in this collection that matches the conditions given in the predicate, or null
/// if no such entry can be found.
/// </summary>
/// <param name="match">The predicate that defines the conditions of the entry to look for.</param>
public KMapForcedColumn<T> Find(Predicate<KMapForcedColumn<T>> match)
{
if (_MetaMap == null) throw new ObjectDisposedException(this.ToString());
if (_MetaMap.IsDisposed) throw new ObjectDisposedException(_MetaMap.ToString());
if (match == null) throw new ArgumentNullException("match", "Predicate cannot be null.");
return _List.Find(match);
}
IKMapForcedColumn IKMapForcedColumnCollection.Find(Predicate<IKMapForcedColumn> match)
{
return this.Find(match);
}
public IEnumerator<KMapForcedColumn<T>> GetEnumerator()
{
if (_MetaMap == null) throw new ObjectDisposedException(this.ToString());
if (_MetaMap.IsDisposed) throw new ObjectDisposedException(_MetaMap.ToString());
return _List.GetEnumerator();
}
IEnumerator<IKMapForcedColumn> IEnumerable<IKMapForcedColumn>.GetEnumerator()
{
return this.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
}
// ========================================================