Click here to Skip to main content
15,892,927 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 System.Diagnostics;
using System.Security.Permissions;
using BrainTechLLC.ThreadSafeObjects;
using System.Web;

namespace BrainTechLLC.DAL
{
	/// <summary>
	/// LookupCollection handles the QuickLookup and AltLookup attributes on a property (basically, in-memory, static indices)
	/// </summary>
	/// <typeparam name="TP"></typeparam>
	[DataObject(true), AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Medium)]
	public class LookupCollection<TP> where TP : DBLayer<TP>, IDBLayer<TP>, new()
	{
		internal PropertyDescriptor _indexedProperty;
		internal ThreadSafeLookup<long , TP> _quickLookup;
		internal CollectionCacheable _cache;

		public LookupCollection(PropertyDescriptor propIndexed) { _indexedProperty = propIndexed; }
		public LookupCollection() { }

		/// <summary>
		/// Sanity checking (class is cacheable, has quick or alternative lookup set)
		/// </summary>
		/// <returns></returns>
		internal bool CommonCheck()
		{
			if (_indexedProperty == null)
			{
				_indexedProperty = DBLayer<TP>.CachedAttributes.QuickLookupProperty;
				if (_indexedProperty == null)
				{
					Debug.Assert(false, "No Property found marked with the QuickLookup attribute");
					return false;
				}
			}
			if (_cache == null)
			{
				_cache = DBLayer<TP>.Cache.CollectionCacheableAttribute;
				if (_cache == null)
				{
					Debug.Assert(false, "This class has not been marked as Cacheable");
					return false;
				}
			}
			return true;
		}

		/// <summary>
		/// Make sure the user indexed the property using an appropriate type
		/// </summary>
		/// <param name="indexerType"></param>
		/// <returns></returns>
		protected bool CheckType(Type indexerType)
		{
//#if LoggingOn
//            if (_indexedProperty.PropertyType != indexerType)
//            {
//                DALQueryInfo.AddMessage("Index this Property with " + _indexedProperty.PropertyType.Name + " values");
//                return false;
//            }
//#endif
			return true;
		}

		#region "RawGet"
		protected TP RawGet(long hash, object keyVal)
		{
			DBLayer<TP>.Cache.CheckCache();
			TP ret;

			if (_quickLookup == null) { return default(TP); }
			if (_quickLookup.TryGetValue(hash, out ret)) { return ret; }

			if (DBLayer<TP>.Cache.CacheType == CacheType.GrowingCache)
			{
				if (keyVal.ToString() == "0") return null;

				DBWhere where = new DBWhere(_indexedProperty.Name, keyVal);

				ret = DBLayer<TP>.GetSingleRowFrom(where, QuerySourceFlags.FromDatabase, false);
				return ret;
			}

			return ret;
		}
		#endregion

		/// <summary>
		/// Determines which Quick lookup field to use
		/// </summary>
		/// <returns></returns>
		internal bool CheckIndexed()
		{
			if (_indexedProperty != null) return true;
			else
			{
				_indexedProperty = DBLayer<TP>.CachedAttributes.QuickLookupProperty;
				return (_indexedProperty != null);
			}
		}

		#region "Indexers"
		public TP this[string s]
		{
			get
			{
				if (!CheckIndexed() || !CommonCheck() || !CheckType(typeof(string))) return default(TP);
				long hash = (long)s.GetHashCode();
				return RawGet(hash, s);
			}
		}

		public TP this[int idx]
		{
			get
			{
				if (!CheckIndexed() || !CommonCheck() || !CheckType(typeof(int))) return default(TP);
				return RawGet((long)idx, idx);
			}
		}

		public TP this[long idx]
		{
			get
			{
				if (!CheckIndexed() || !CommonCheck() || !CheckType(typeof(int))) return default(TP);
				return RawGet(idx, idx);
			}
		}

		public TP this[short idx]
		{
			get
			{
				if (!CheckIndexed() || !CommonCheck() || !CheckType(typeof(short))) return default(TP);
				return RawGet((long)idx, idx);
			}
		}

		public TP this[char c]
		{
			get
			{
				if (!CheckIndexed() || !CommonCheck() || !CheckType(typeof(char))) return default(TP);
				return RawGet((long)c, c);
			}
		}

		public TP this[byte idx]
		{
			get
			{
				if (!CheckIndexed() || !CommonCheck() || !CheckType(typeof(byte))) return default(TP);
				return RawGet((long)idx, idx);
			}
		}

		public TP this[object idx]
		{
			get
			{
				if (!CommonCheck()) return default(TP);
				return RawGet((long)idx.GetHashCode(), idx);
			}
		}
		#endregion
	}
}

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