/// <summary> /// Gets the name of the table. /// </summary> /// <param name="type">The type.</param> /// <returns></returns> /// <exception cref="System.ApplicationException">Failed to resolve TableName for Type: + type.FullName</exception> private static string GetTableName(Type type) { StringCacheData cacheData; if (_cachedTypeTableNames.TryGetValue(type.TypeHandle, out cacheData)) { var expired = CacheExpirationTicks; if (cacheData.LastAccess < expired) { // If expired, remove from cache StringCacheData removed; _cachedTypeTableNames.TryRemove(type.TypeHandle, out removed); } else { // If not expired, update last access and return it var updated = cacheData.Clone(); _cachedTypeTableNames.TryUpdate(type.TypeHandle, updated, cacheData); return(updated.Data); } } // Default table name is class name var name = type.Name; // Remove interface prefix, if any if (type.IsInterface && name.StartsWith("I")) { name = name.Substring(1); } // Support decoration using TableAttribute // NOTE: This as dynamic trick should be able to handle both our own Table-attribute as well as the one in EntityFramework var tableattr = type.GetCustomAttributes(false).Where(attr => attr.GetType().Name == "TableAttribute").SingleOrDefault() as dynamic; if (tableattr != null) { name = tableattr.Name; } // Guard against null table name if (string.IsNullOrWhiteSpace(name)) { throw new ApplicationException("Failed to resolve TableName for Type: " + type.FullName); } // Cache mapping cacheData = new StringCacheData(name); _cachedTypeTableNames.TryAdd(type.TypeHandle, cacheData); return(cacheData.Data); }
/// <summary> /// Returns a single entity by a single id from table "T". /// If T is an interface a proxy is generated. /// Id must be marked with [Key] attribute. /// Entity is tracked/intercepted for changes and used by the Update() extension. /// </summary> /// <typeparam name="T">Entity Type</typeparam> /// <param name="connection">Open SqlConnection</param> /// <param name="id">Id of the entity to get, must be marked with [Key] attribute</param> /// <returns>Entity of T</returns> public static T Get <T>(this IDbConnection connection, dynamic id, IDbTransaction transaction = null, int?commandTimeout = null) where T : class { // Argument Validation if (connection == null) { throw new ArgumentNullException("connection", "connection cannot be null"); } if (id == null) { throw new ArgumentNullException("id", "id cannot be null"); } InitializeCacheSweeper(); var type = typeof(T); StringCacheData cacheData; // Retrieve cached query if (!_cachedQueries.TryGetValue(type.TypeHandle, out cacheData)) { var keys = KeyPropertiesCache(type); if (keys.Count() > 1) { throw new DataException("Get<T> only supports an entity with a single [Key] property"); } if (keys.Count() == 0) { throw new DataException("Get<T> only supports an entity with a [Key] property"); } var onlyKey = keys.First(); var name = GetTableName(type); // TODO: query information schema and only select fields that are both in information schema and underlying class / interface var sql = "select * from " + name + " where " + onlyKey.Name + " = @id"; cacheData = new StringCacheData(sql); _cachedQueries.TryAdd(type.TypeHandle, cacheData); } // Build parameters var dynParms = new Dapper.DynamicParameters(); dynParms.Add("@id", id); T obj = null; // Processing //if (type.IsInterface) // Create proxy if interface //{ // // Execute // var res = connection.Query(cacheData.Data, dynParms).SingleOrDefault() as IDictionary<string, object>; // if (res == null) return (T)((object)null); // // Create proxy // obj = ProxyGenerator.GetInterfaceProxy<T>(); // // Map properties // foreach (var property in TypePropertiesCache(type)) // { // var val = res[property.Name]; // property.SetValue(obj, val, null); // } // // Reset change tracking // ((IProxy)obj).IsDirty = false; //} //else //{ //obj = connection.Query<T>(cacheData.Data, dynParms, transaction: transaction, commandTimeout: commandTimeout).SingleOrDefault(); //} ISqlAdapter adapter = GetFormatter(connection); obj = adapter.Get <T>(connection, transaction, commandTimeout, cacheData.Data, dynParms); return(obj); }