Click here to Skip to main content
15,891,372 members
Articles / Programming Languages / C#

Design and Implementation of an Attribute-Driven, Caching Data Abstraction Layer

Rate me:
Please Sign up or sign in to vote.
4.98/5 (25 votes)
21 Jul 2008CPOL30 min read 68.7K   595   103  
An easy-to-use, attribute-driven data abstraction layer with multi-database support, intelligent caching, transparent encryption, multi-property sorting, property change tracking, etc.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using BrainTechLLC.ThreadSafeObjects;
using Hyper.ComponentModel;

namespace BrainTechLLC.ThreadSafeObjects
{
	/// <summary>
	/// Thread-safe lookup allows multiple threads to look up items by key, add items,
	/// and remove items in a thread-safe manner
	/// </summary>
	/// <typeparam name="TListType"></typeparam>
	/// <typeparam name="TIndex"></typeparam>
	[TypeDescriptionProvider(typeof(HyperTypeDescriptionProvider)), Serializable]
	public class ThreadSafeLookup<TIndex, TListType> : Lockable, IMultipleItems<TListType>,
	   ISupportsCount, ISupportsAddRemoveClear<TIndex, TListType> where TListType : class
	{
		public Dictionary<TIndex, TListType> Lookup = new Dictionary<TIndex, TListType>();
		public TListType[] ArrayOfItems { get { return AllItems.ToArray(); } }
		public int Count { get { return Lookup.Count; } }

		public bool ContainsKey(TIndex key) { return Lookup.ContainsKey(key); }
		public bool TryGetValue(TIndex key, out TListType items) { return Lookup.TryGetValue(key, out items); }

		public List<TListType> AllItems
		{
			get
			{
				List<TListType> items = new List<TListType>(Lookup.Count);

				AquireLock();
				{
					foreach (KeyValuePair<TIndex, TListType> kvp in Lookup)
						items.Add(kvp.Value);
				}
				ReleaseLock();

				return items;
			}
		}

		public bool Add(TIndex key, TListType item)
		{
			bool found = true;

			AquireLock();
			{
				if (!Lookup.ContainsKey(key))
				{
					Lookup.Add(key, item);
					found = false;
				}
			}
			ReleaseLock();

			return found;
		}

		public void AddOrSet(TIndex key, TListType item)
		{
			if (Lookup.ContainsKey(key))
			{
				Lookup[key] = item;
			}
			else
			{
				Add(key, item);
			}
		}

		public TListType this[TIndex key]
		{
			get
			{
				TListType item;

				// Not totally safe for lookups that frequently add/remove items.
				// For thread safety, surround the following line with AquireLock(); / ReleaseLock();
				if (!Lookup.TryGetValue(key, out item)) item = default(TListType);

				return item;
			}
		}

		public bool Remove(TIndex key, TListType item)
		{
			bool removed = false;

			if (!Lookup.ContainsKey(key))
				return false;

			AquireLock();
			{
				if (Lookup.ContainsKey(key))
				{
					Lookup.Remove(key);
					removed = true;
				}
			}
			ReleaseLock();

			return removed;
		}

		public bool Remove(TIndex key)
		{
			bool removed = false;

			if (!Lookup.ContainsKey(key))
				return false;

			AquireLock();
			{
				if (Lookup.ContainsKey(key))
				{
					Lookup.Remove(key);
					removed = true;
				}
			}
			ReleaseLock();

			return removed;
		}

		public void Clear()
		{
			AquireLock();
			{
				Lookup.Clear();
			}
			ReleaseLock();
		}
	}

	/// <summary>
	/// Thread-safe lookup allows multiple threads to look up items by key, add items,
	/// and remove items in a thread-safe manner
	/// </summary>
	/// <typeparam name="TListType"></typeparam>
	/// <typeparam name="TIndex"></typeparam>
	[TypeDescriptionProvider(typeof(HyperTypeDescriptionProvider)), Serializable]
	public class ThreadSafeLookupOnAutoKey<TIndex, TListType> : ThreadSafeLookup<TIndex, TListType>, IMultipleItems<TListType>,
	   ISupportsCount, ISupportsAddRemoveClear<TIndex, TListType> where TListType : class, IKeyedOnProperty<TIndex>
	{
		public bool Add(TListType item)
		{
			TIndex key = item.Key;
			return Add(key, item);
		}

		public void AddOrSet(TListType item)
		{
			TIndex key = item.Key;
			AddOrSet(key, item);
		}

		public bool Remove(TListType item)
		{
			TIndex key = item.Key;
			return Remove(item.Key);
		}
	}

	/// <summary>
	/// Thread-safe lookup allows multiple threads to look up items by key, add items,
	/// and remove items in a thread-safe manner
	/// </summary>
	/// <typeparam name="TListType"></typeparam>
	/// <typeparam name="TIndex"></typeparam>
	[TypeDescriptionProvider(typeof(HyperTypeDescriptionProvider)), Serializable]
	public class ThreadSafeLookupNonRef<TIndex, TListType> : Lockable, IMultipleItems<TListType>,
	   ISupportsCount
	{
		public Dictionary<TIndex, TListType> Lookup = new Dictionary<TIndex, TListType>();
		public TListType[] ArrayOfItems { get { return AllItems.ToArray(); } }
		public int Count { get { return Lookup.Count; } }

		public bool ContainsKey(TIndex key) { return Lookup.ContainsKey(key); }
		public bool TryGetValue(TIndex key, out TListType items) { return Lookup.TryGetValue(key, out items); }

		public List<TListType> AllItems
		{
			get
			{
				List<TListType> items = new List<TListType>(Lookup.Count);

				AquireLock();
				{
					foreach (KeyValuePair<TIndex, TListType> kvp in Lookup)
						items.Add(kvp.Value);
				}
				ReleaseLock();

				return items;
			}
		}

		public bool Add(TIndex key, TListType item)
		{
			bool found = true;

			AquireLock();
			{
				if (!Lookup.ContainsKey(key))
				{
					Lookup.Add(key, item);
					found = false;
				}
			}
			ReleaseLock();

			return found;
		}

		public void AddOrSet(TIndex key, TListType item)
		{
			if (Lookup.ContainsKey(key))
			{
				Lookup[key] = item;
			}
			else
			{
				Add(key, item);
			}
		}

		public TListType this[TIndex key]
		{
			get
			{
				TListType item;

				// Not totally safe for lookups that frequently add/remove items.
				// For thread safety, surround the following line with AquireLock(); / ReleaseLock();
				if (!Lookup.TryGetValue(key, out item)) item = default(TListType);

				return item;
			}
		}

		public bool Remove(TIndex key, TListType item)
		{
			bool removed = false;

			if (!Lookup.ContainsKey(key))
				return false;

			AquireLock();
			{
				if (Lookup.ContainsKey(key))
				{
					Lookup.Remove(key);
					removed = true;
				}
			}
			ReleaseLock();

			return removed;
		}

		public bool Remove(TIndex key)
		{
			bool removed = false;

			if (!Lookup.ContainsKey(key))
				return false;

			AquireLock();
			{
				if (Lookup.ContainsKey(key))
				{
					Lookup.Remove(key);
					removed = true;
				}
			}
			ReleaseLock();

			return removed;
		}

		public void Clear()
		{
			AquireLock();
			{
				Lookup.Clear();
			}
			ReleaseLock();
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Troppus Software
United States United States
Currently working as a Senior Silverlight Developer with Troppus Software in Superior, CO. I enjoy statistics, programming, new technology, playing the cello, and reading codeproject articles. Smile | :)

Comments and Discussions