private SqlClientCrudAdapter(string connectionString, string tableName, string keyName, bool isIdentity)
            : base
            (
                /* create */
                (e) =>
        {
            var t          = typeof(T);
            var parameters = (isIdentity ? _fieldListWithoutKey : _fieldList)
                             .Select(f => new { Key = f, Value = t.GetProperty(f).GetValue(e) }).ToDictionary(p => p.Key, p => p.Value);
            var ret = Execute(_insertCommand, parameters, isIdentity);
            if (isIdentity)
            {
                var prop = t.GetProperty(keyName);
                prop.SetValue(e, Convert.ChangeType(ret, prop.PropertyType));
            }
        },

                /* update */
                (e) =>
        {
            var t          = typeof(T);
            var parameters = _fieldList.Select(f => new { Key = f, Value = t.GetProperty(f).GetValue(e) }).ToDictionary(p => p.Key, p => p.Value);
            Execute(_updateCommand, parameters);
        },

                /* delete */
                (e) =>
        {
            var parameters = new Dictionary <string, object>()
            {
                { keyName, typeof(T).GetProperty(keyName).GetValue(e) }
            };
            Execute(_deleteCommand, parameters);
        },

                /* read */
                (predicate) =>
        {
            return(Enumerable.Empty <T>().AsQueryable());
        },

                /* read */
                (sql, parameters) =>
        {
            return(Enumerable.Empty <T>().AsQueryable());
        }
            )
        {
            if (_fieldList == null)
            {
                _fieldList           = typeof(T).GetProperties().Where(p => p.PropertyType.IsSealed && p.GetAccessors().Any(a => !(a.IsVirtual && !a.IsFinal) && a.ReturnType == typeof(void))).Select(p => p.Name).ToList();
                _fieldListWithoutKey = _fieldList.Where(f => !string.Equals(f, keyName, StringComparison.OrdinalIgnoreCase)).ToList();

                _insertCommand = string.Format("INSERT INTO [{0}] ({1}) VALUES ({2}){3}", tableName,
                                               string.Join(", ", _fieldListWithoutKey.Select(f => string.Format("[{0}]", f))),
                                               string.Join(", ", _fieldListWithoutKey.Select(f => string.Format("@{0}", f))),
                                               isIdentity ? "; SELECT CAST(SCOPE_IDENTITY() AS INT);" : "");

                _updateCommand = string.Format("UPDATE [{0}] SET {1} WHERE {2}", tableName,
                                               string.Join(", ", _fieldListWithoutKey.Select(f => string.Format("[{0}] = @{0}", f))),
                                               string.Format("[{0}] = @{0}", keyName));

                _deleteCommand = string.Format("DELETE [{0}] WHERE {1}", tableName,
                                               string.Format("[{0}] = @{0}", keyName));

                _connectionString = connectionString;
            }

            var sqlClientQueryAdapterType = typeof(SqlClientQueryAdapter <>).MakeGenericType(new[] { typeof(T) });
            _queryAdapter = (DelegateQueryAdapter <T>)Activator.CreateInstance(sqlClientQueryAdapterType, connectionString, tableName);
        }
        private InMemoryCrudAdapter(IList <T> source, string keyName, bool isIdentity)
            : base
            (
                /* create */
                (e) =>
        {
            var t = typeof(T);

            if (isIdentity)
            {
                var param = Expression.Parameter(t, "e");
                var prop  = Expression.Property(param, keyName);

                var selector = Expression.Lambda(prop, param);

                var nextId = (source.Any() ? source.Max((Func <T, int>)selector.Compile()) : 0) + 1;
                t.GetProperty(keyName).SetValue(e, nextId);
            }

            var entry = new T();
            foreach (var field in _fieldList)
            {
                var f = t.GetProperty(field);
                f.SetValue(entry, f.GetValue(e));
            }

            source.Add(entry);
        },

                /* update */
                (e) =>
        {
            var entry = source.FirstOrDefault(CreatePredicate(e, keyName));
            if (entry != null)
            {
                var t = typeof(T);
                foreach (var field in _fieldListWithoutKey)
                {
                    var f = t.GetProperty(field);
                    f.SetValue(entry, f.GetValue(e));
                }
            }
        },

                /* delete */
                (e) =>
        {
            var entry = source.FirstOrDefault(CreatePredicate(e, keyName));
            if (entry != null)
            {
                source.Remove(entry);
            }
        },

                /* read */
                (predicate) =>
        {
            return(Enumerable.Empty <T>().AsQueryable());
        },

                /* read */
                (sql, parameters) =>
        {
            return(Enumerable.Empty <T>().AsQueryable());
        }
            )
        {
            if (_fieldList == null)
            {
                _fieldList           = typeof(T).GetProperties().Where(p => p.PropertyType.IsSealed && p.GetAccessors().Any(a => !(a.IsVirtual && !a.IsFinal) && a.ReturnType == typeof(void))).Select(p => p.Name).ToList();
                _fieldListWithoutKey = _fieldList.Where(f => !string.Equals(f, keyName, StringComparison.OrdinalIgnoreCase)).ToList();
            }

            var inMemoryQueryAdapterType = typeof(InMemoryQueryAdapter <>).MakeGenericType(new[] { typeof(T) });
            _queryAdapter = (DelegateQueryAdapter <T>)Activator.CreateInstance(inMemoryQueryAdapterType, source);
        }