如下代码,修改成只支持oracle:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.Linq;
  5. using System.Reflection;
  6. using System.Text;
  7. using System.Collections.Concurrent;
  8. using System.Reflection.Emit;
  9.  
  10. using Dapper;
  11. using System.Threading;
  12. using System.Threading.Tasks;
  13.  
  14. namespace Dapper.Contrib.Extensions
  15. {
  16. /// <summary>
  17. /// The Dapper.Contrib extensions for Dapper
  18. /// </summary>
  19. public static partial class SqlMapperExtensions
  20. {
  21. /// <summary>
  22. /// Defined a proxy object with a possibly dirty state.
  23. /// </summary>
  24. public interface IProxy //must be kept public
  25. {
  26. /// <summary>
  27. /// Whether the object has been changed.
  28. /// </summary>
  29. bool IsDirty { get; set; }
  30. }
  31.  
  32. /// <summary>
  33. /// Defines a table name mapper for getting table names from types.
  34. /// </summary>
  35. public interface ITableNameMapper
  36. {
  37. /// <summary>
  38. /// Gets a table name from a given <see cref="Type"/>.
  39. /// </summary>
  40. /// <param name="type">The <see cref="Type"/> to get a name from.</param>
  41. /// <returns>The table name for the given <paramref name="type"/>.</returns>
  42. string GetTableName(Type type);
  43. }
  44.  
  45. /// <summary>
  46. /// The function to get a database type from the given <see cref="IDbConnection"/>.
  47. /// </summary>
  48. /// <param name="connection">The connection to get a database type name from.</param>
  49. public delegate string GetDatabaseTypeDelegate(IDbConnection connection);
  50. /// <summary>
  51. /// The function to get a a table name from a given <see cref="Type"/>
  52. /// </summary>
  53. /// <param name="type">The <see cref="Type"/> to get a table name for.</param>
  54. public delegate string TableNameMapperDelegate(Type type);
  55.  
  56. private static readonly ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>> KeyProperties = new ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>>();
  57. private static readonly ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>> ExplicitKeyProperties = new ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>>();
  58. private static readonly ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>> TypeProperties = new ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>>();
  59. private static readonly ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>> ComputedProperties = new ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>>();
  60. private static readonly ConcurrentDictionary<RuntimeTypeHandle, string> GetQueries = new ConcurrentDictionary<RuntimeTypeHandle, string>();
  61. private static readonly ConcurrentDictionary<RuntimeTypeHandle, string> TypeTableName = new ConcurrentDictionary<RuntimeTypeHandle, string>();
  62.  
  63. private static readonly ISqlAdapter DefaultAdapter = new SqlServerAdapter();
  64. private static readonly Dictionary<string, ISqlAdapter> AdapterDictionary
  65. = new Dictionary<string, ISqlAdapter>
  66. {
  67. ["sqlconnection"] = new SqlServerAdapter(),
  68. ["oracleconnection"] = new OracleAdapter(),
  69. ["sqlceconnection"] = new SqlCeServerAdapter(),
  70. ["mysqlconnection"] = new MySqlAdapter()
  71. };
  72.  
  73. private static List<PropertyInfo> ComputedPropertiesCache(Type type)
  74. {
  75. if (ComputedProperties.TryGetValue(type.TypeHandle, out IEnumerable<PropertyInfo> pi))
  76. {
  77. return pi.ToList();
  78. }
  79.  
  80. var computedProperties = TypePropertiesCache(type).Where(p => p.GetCustomAttributes(true).Any(a => a is ComputedAttribute)).ToList();
  81.  
  82. ComputedProperties[type.TypeHandle] = computedProperties;
  83. return computedProperties;
  84. }
  85.  
  86. private static List<PropertyInfo> ExplicitKeyPropertiesCache(Type type)
  87. {
  88. if (ExplicitKeyProperties.TryGetValue(type.TypeHandle, out IEnumerable<PropertyInfo> pi))
  89. {
  90. return pi.ToList();
  91. }
  92.  
  93. var explicitKeyProperties = TypePropertiesCache(type).Where(p => p.GetCustomAttributes(true).Any(a => a is ExplicitKeyAttribute)).ToList();
  94.  
  95. ExplicitKeyProperties[type.TypeHandle] = explicitKeyProperties;
  96. return explicitKeyProperties;
  97. }
  98.  
  99. private static List<PropertyInfo> KeyPropertiesCache(Type type)
  100. {
  101. if (KeyProperties.TryGetValue(type.TypeHandle, out IEnumerable<PropertyInfo> pi))
  102. {
  103. return pi.ToList();
  104. }
  105.  
  106. var allProperties = TypePropertiesCache(type);
  107. var keyProperties = allProperties.Where(p => p.GetCustomAttributes(true).Any(a => a is KeyAttribute)).ToList();
  108.  
  109. if (keyProperties.Count == )
  110. {
  111. var idProp = allProperties.Find(p => string.Equals(p.Name, "id", StringComparison.CurrentCultureIgnoreCase));
  112. if (idProp != null && !idProp.GetCustomAttributes(true).Any(a => a is ExplicitKeyAttribute))
  113. {
  114. keyProperties.Add(idProp);
  115. }
  116. }
  117.  
  118. KeyProperties[type.TypeHandle] = keyProperties;
  119. return keyProperties;
  120. }
  121.  
  122. private static List<PropertyInfo> TypePropertiesCache(Type type)
  123. {
  124. if (TypeProperties.TryGetValue(type.TypeHandle, out IEnumerable<PropertyInfo> pis))
  125. {
  126. return pis.ToList();
  127. }
  128.  
  129. var properties = type.GetProperties().Where(IsWriteable).ToArray();
  130. TypeProperties[type.TypeHandle] = properties;
  131. return properties.ToList();
  132. }
  133.  
  134. private static bool IsWriteable(PropertyInfo pi)
  135. {
  136. var attributes = pi.GetCustomAttributes(typeof(WriteAttribute), false).AsList();
  137. if (attributes.Count != ) return true;
  138.  
  139. var writeAttribute = (WriteAttribute)attributes[];
  140. return writeAttribute.Write;
  141. }
  142.  
  143. private static PropertyInfo GetSingleKey<T>(string method)
  144. {
  145. var type = typeof(T);
  146. var keys = KeyPropertiesCache(type);
  147. var explicitKeys = ExplicitKeyPropertiesCache(type);
  148. var keyCount = keys.Count + explicitKeys.Count;
  149. if (keyCount > )
  150. throw new DataException($"{method}<T> only supports an entity with a single [Key] or [ExplicitKey] property");
  151. if (keyCount == )
  152. throw new DataException($"{method}<T> only supports an entity with a [Key] or an [ExplicitKey] property");
  153.  
  154. return keys.Count > ? keys[] : explicitKeys[];
  155. }
  156.  
  157. /// <summary>
  158. /// Returns a single entity by a single id from table "Ts".
  159. /// Id must be marked with [Key] attribute.
  160. /// Entities created from interfaces are tracked/intercepted for changes and used by the Update() extension
  161. /// for optimal performance.
  162. /// </summary>
  163. /// <typeparam name="T">Interface or type to create and populate</typeparam>
  164. /// <param name="connection">Open SqlConnection</param>
  165. /// <param name="id">Id of the entity to get, must be marked with [Key] attribute</param>
  166. /// <param name="transaction">The transaction to run under, null (the default) if none</param>
  167. /// <param name="commandTimeout">Number of seconds before command execution timeout</param>
  168. /// <returns>Entity of T</returns>
  169. public static T Get<T>(this IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
  170. {
  171. var type = typeof(T);
  172.  
  173. if (!GetQueries.TryGetValue(type.TypeHandle, out string sql))
  174. {
  175. var key = GetSingleKey<T>(nameof(Get));
  176. var name = GetTableName(type);
  177.  
  178. sql = $"SELECT * FROM {name} WHERE {key.Name} = :id";
  179. GetQueries[type.TypeHandle] = sql;
  180. }
  181.  
  182. var dynParms = new DynamicParameters();
  183. dynParms.Add(":id", id);
  184.  
  185. T obj;
  186.  
  187. if (type.IsInterface())
  188. {
  189. var res = connection.Query(sql, dynParms).FirstOrDefault() as IDictionary<string, object>;
  190.  
  191. if (res == null)
  192. return null;
  193.  
  194. obj = ProxyGenerator.GetInterfaceProxy<T>();
  195.  
  196. foreach (var property in TypePropertiesCache(type))
  197. {
  198. var val = res[property.Name];
  199. property.SetValue(obj, Convert.ChangeType(val, property.PropertyType), null);
  200. }
  201.  
  202. ((IProxy)obj).IsDirty = false; //reset change tracking and return
  203. }
  204. else
  205. {
  206. obj = connection.Query<T>(sql, dynParms, transaction, commandTimeout: commandTimeout).FirstOrDefault();
  207. }
  208. return obj;
  209. }
  210.  
  211. /// <summary>
  212. /// Returns a list of entites from table "Ts".
  213. /// Id of T must be marked with [Key] attribute.
  214. /// Entities created from interfaces are tracked/intercepted for changes and used by the Update() extension
  215. /// for optimal performance.
  216. /// </summary>
  217. /// <typeparam name="T">Interface or type to create and populate</typeparam>
  218. /// <param name="connection">Open SqlConnection</param>
  219. /// <param name="transaction">The transaction to run under, null (the default) if none</param>
  220. /// <param name="commandTimeout">Number of seconds before command execution timeout</param>
  221. /// <returns>Entity of T</returns>
  222. public static IEnumerable<T> GetAll<T>(this IDbConnection connection, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
  223. {
  224. var type = typeof(T);
  225. var cacheType = typeof(List<T>);
  226.  
  227. if (!GetQueries.TryGetValue(cacheType.TypeHandle, out string sql))
  228. {
  229. GetSingleKey<T>(nameof(GetAll));
  230. var name = GetTableName(type);
  231.  
  232. sql = "SELECT * FROM " + name;
  233. GetQueries[cacheType.TypeHandle] = sql;
  234. }
  235.  
  236. if (!type.IsInterface()) return connection.Query<T>(sql, null, transaction, commandTimeout: commandTimeout);
  237.  
  238. var result = connection.Query(sql);
  239. var list = new List<T>();
  240. foreach (IDictionary<string, object> res in result)
  241. {
  242. var obj = ProxyGenerator.GetInterfaceProxy<T>();
  243. foreach (var property in TypePropertiesCache(type))
  244. {
  245. var val = res[property.Name];
  246. property.SetValue(obj, Convert.ChangeType(val, property.PropertyType), null);
  247. }
  248. ((IProxy)obj).IsDirty = false; //reset change tracking and return
  249. list.Add(obj);
  250. }
  251. return list;
  252. }
  253.  
  254. /// <summary>
  255. /// Specify a custom table name mapper based on the POCO type name
  256. /// </summary>
  257. public static TableNameMapperDelegate TableNameMapper;
  258.  
  259. private static string GetTableName(Type type)
  260. {
  261. if (TypeTableName.TryGetValue(type.TypeHandle, out string name)) return name;
  262.  
  263. if (TableNameMapper != null)
  264. {
  265. name = TableNameMapper(type);
  266. }
  267. else
  268. {
  269. //NOTE: This as dynamic trick should be able to handle both our own Table-attribute as well as the one in EntityFramework
  270. var tableAttr = type
  271. #if NETSTANDARD1_3
  272. .GetTypeInfo()
  273. #endif
  274. .GetCustomAttributes(false).SingleOrDefault(attr => attr.GetType().Name == "TableAttribute") as dynamic;
  275. if (tableAttr != null)
  276. {
  277. name = tableAttr.Name;
  278. }
  279. else
  280. {
  281. name = type.Name;// + "s";
  282. if (type.IsInterface() && name.StartsWith("I"))
  283. name = name.Substring();
  284. }
  285. }
  286.  
  287. TypeTableName[type.TypeHandle] = name;
  288. return name;
  289. }
  290.  
  291. /// <summary>
  292. /// Inserts an entity into table "Ts" and returns identity id or number if inserted rows if inserting a list.
  293. /// </summary>
  294. /// <typeparam name="T">The type to insert.</typeparam>
  295. /// <param name="connection">Open SqlConnection</param>
  296. /// <param name="entityToInsert">Entity to insert, can be list of entities</param>
  297. /// <param name="transaction">The transaction to run under, null (the default) if none</param>
  298. /// <param name="commandTimeout">Number of seconds before command execution timeout</param>
  299. /// <returns>Identity of inserted entity, or number of inserted rows if inserting a list</returns>
  300. public static long Insert<T>(this IDbConnection connection, T entityToInsert, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
  301. {
  302. var isList = false;
  303.  
  304. var type = typeof(T);
  305.  
  306. if (type.IsArray)
  307. {
  308. isList = true;
  309. type = type.GetElementType();
  310. }
  311. else if (type.IsGenericType())
  312. {
  313. isList = true;
  314. type = type.GetGenericArguments()[];
  315. }
  316.  
  317. var name = GetTableName(type);
  318. var sbColumnList = new StringBuilder(null);
  319. var allProperties = TypePropertiesCache(type);
  320. var keyProperties = KeyPropertiesCache(type);
  321. var computedProperties = ComputedPropertiesCache(type);
  322. var allPropertiesExceptKeyAndComputed = allProperties.Except(keyProperties.Union(computedProperties)).ToList();
  323.  
  324. var adapter = GetFormatter(connection);
  325.  
  326. for (var i = ; i < allPropertiesExceptKeyAndComputed.Count; i++)
  327. {
  328. var property = allPropertiesExceptKeyAndComputed[i];
  329. adapter.AppendColumnName(sbColumnList, property.Name); //fix for issue #336
  330. if (i < allPropertiesExceptKeyAndComputed.Count - )
  331. sbColumnList.Append(", ");
  332. }
  333.  
  334. var sbParameterList = new StringBuilder(null);
  335. for (var i = ; i < allPropertiesExceptKeyAndComputed.Count; i++)
  336. {
  337. var property = allPropertiesExceptKeyAndComputed[i];
  338. sbParameterList.AppendFormat(":{0}", property.Name);
  339. if (i < allPropertiesExceptKeyAndComputed.Count - )
  340. sbParameterList.Append(", ");
  341. }
  342.  
  343. int returnVal;
  344. var wasClosed = connection.State == ConnectionState.Closed;
  345. if (wasClosed) connection.Open();
  346.  
  347. if (!isList) //single entity
  348. {
  349. returnVal = adapter.Insert(connection, transaction, commandTimeout, name, sbColumnList.ToString(),
  350. sbParameterList.ToString(), keyProperties, entityToInsert);
  351. }
  352. else
  353. {
  354. //insert list of entities
  355. var cmd = $"INSERT INTO {name} ({sbColumnList}) VALUES ({sbParameterList})";
  356. returnVal = connection.Execute(cmd, entityToInsert, transaction, commandTimeout);
  357. }
  358. if (wasClosed) connection.Close();
  359. return returnVal;
  360. }
  361.  
  362. /// <summary>
  363. /// Updates entity in table "Ts", checks if the entity is modified if the entity is tracked by the Get() extension.
  364. /// </summary>
  365. /// <typeparam name="T">Type to be updated</typeparam>
  366. /// <param name="connection">Open SqlConnection</param>
  367. /// <param name="entityToUpdate">Entity to be updated</param>
  368. /// <param name="transaction">The transaction to run under, null (the default) if none</param>
  369. /// <param name="commandTimeout">Number of seconds before command execution timeout</param>
  370. /// <returns>true if updated, false if not found or not modified (tracked entities)</returns>
  371. public static bool Update<T>(this IDbConnection connection, T entityToUpdate, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
  372. {
  373. if (entityToUpdate is IProxy proxy && !proxy.IsDirty)
  374. {
  375. return false;
  376. }
  377.  
  378. var type = typeof(T);
  379.  
  380. if (type.IsArray)
  381. {
  382. type = type.GetElementType();
  383. }
  384. else if (type.IsGenericType())
  385. {
  386. type = type.GetGenericArguments()[];
  387. }
  388.  
  389. var keyProperties = KeyPropertiesCache(type).ToList(); //added ToList() due to issue #418, must work on a list copy
  390. var explicitKeyProperties = ExplicitKeyPropertiesCache(type);
  391. if (keyProperties.Count == && explicitKeyProperties.Count == )
  392. throw new ArgumentException("Entity must have at least one [Key] or [ExplicitKey] property");
  393.  
  394. var name = GetTableName(type);
  395.  
  396. var sb = new StringBuilder();
  397. sb.AppendFormat("UPDATE {0} SET ", name);
  398.  
  399. var allProperties = TypePropertiesCache(type);
  400. keyProperties.AddRange(explicitKeyProperties);
  401. var computedProperties = ComputedPropertiesCache(type);
  402. var nonIdProps = allProperties.Except(keyProperties.Union(computedProperties)).ToList();
  403.  
  404. var adapter = GetFormatter(connection);
  405.  
  406. for (var i = ; i < nonIdProps.Count; i++)
  407. {
  408. var property = nonIdProps[i];
  409. adapter.AppendColumnNameEqualsValue(sb, property.Name); //fix for issue #336
  410. if (i < nonIdProps.Count - )
  411. sb.AppendFormat(", ");
  412. }
  413. sb.Append(" WHERE ");
  414. for (var i = ; i < keyProperties.Count; i++)
  415. {
  416. var property = keyProperties[i];
  417. adapter.AppendColumnNameEqualsValue(sb, property.Name); //fix for issue #336
  418. if (i < keyProperties.Count - )
  419. sb.AppendFormat(" AND ");
  420. }
  421. var updated = connection.Execute(sb.ToString(), entityToUpdate, commandTimeout: commandTimeout, transaction: transaction);
  422. return updated > ;
  423. }
  424.  
  425. /// <summary>
  426. /// Delete entity in table "Ts".
  427. /// </summary>
  428. /// <typeparam name="T">Type of entity</typeparam>
  429. /// <param name="connection">Open SqlConnection</param>
  430. /// <param name="entityToDelete">Entity to delete</param>
  431. /// <param name="transaction">The transaction to run under, null (the default) if none</param>
  432. /// <param name="commandTimeout">Number of seconds before command execution timeout</param>
  433. /// <returns>true if deleted, false if not found</returns>
  434. public static bool Delete<T>(this IDbConnection connection, T entityToDelete, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
  435. {
  436. if (entityToDelete == null)
  437. throw new ArgumentException("Cannot Delete null Object", nameof(entityToDelete));
  438.  
  439. var type = typeof(T);
  440.  
  441. if (type.IsArray)
  442. {
  443. type = type.GetElementType();
  444. }
  445. else if (type.IsGenericType())
  446. {
  447. type = type.GetGenericArguments()[];
  448. }
  449.  
  450. var keyProperties = KeyPropertiesCache(type).ToList(); //added ToList() due to issue #418, must work on a list copy
  451. var explicitKeyProperties = ExplicitKeyPropertiesCache(type);
  452. if (keyProperties.Count == && explicitKeyProperties.Count == )
  453. throw new ArgumentException("Entity must have at least one [Key] or [ExplicitKey] property");
  454.  
  455. var name = GetTableName(type);
  456. keyProperties.AddRange(explicitKeyProperties);
  457.  
  458. var sb = new StringBuilder();
  459. sb.AppendFormat("DELETE FROM {0} WHERE ", name);
  460.  
  461. var adapter = GetFormatter(connection);
  462.  
  463. for (var i = ; i < keyProperties.Count; i++)
  464. {
  465. var property = keyProperties[i];
  466. adapter.AppendColumnNameEqualsValue(sb, property.Name); //fix for issue #336
  467. if (i < keyProperties.Count - )
  468. sb.AppendFormat(" AND ");
  469. }
  470. var deleted = connection.Execute(sb.ToString(), entityToDelete, transaction, commandTimeout);
  471. return deleted > ;
  472. }
  473.  
  474. /// <summary>
  475. /// Delete all entities in the table related to the type T.
  476. /// </summary>
  477. /// <typeparam name="T">Type of entity</typeparam>
  478. /// <param name="connection">Open SqlConnection</param>
  479. /// <param name="transaction">The transaction to run under, null (the default) if none</param>
  480. /// <param name="commandTimeout">Number of seconds before command execution timeout</param>
  481. /// <returns>true if deleted, false if none found</returns>
  482. public static bool DeleteAll<T>(this IDbConnection connection, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
  483. {
  484. var type = typeof(T);
  485. var name = GetTableName(type);
  486. var statement = $"DELETE FROM {name}";
  487. var deleted = connection.Execute(statement, null, transaction, commandTimeout);
  488. return deleted > ;
  489. }
  490.  
  491. /// <summary>
  492. /// Specifies a custom callback that detects the database type instead of relying on the default strategy (the name of the connection type object).
  493. /// Please note that this callback is global and will be used by all the calls that require a database specific adapter.
  494. /// </summary>
  495. public static GetDatabaseTypeDelegate GetDatabaseType;
  496.  
  497. private static ISqlAdapter GetFormatter(IDbConnection connection)
  498. {
  499. var name = GetDatabaseType?.Invoke(connection).ToLower()
  500. ?? connection.GetType().Name.ToLower();
  501.  
  502. return !AdapterDictionary.ContainsKey(name)
  503. ? DefaultAdapter
  504. : AdapterDictionary[name];
  505. }
  506.  
  507. private static class ProxyGenerator
  508. {
  509. private static readonly Dictionary<Type, Type> TypeCache = new Dictionary<Type, Type>();
  510.  
  511. private static AssemblyBuilder GetAsmBuilder(string name)
  512. {
  513. #if NETSTANDARD1_3 || NETSTANDARD2_0
  514. return AssemblyBuilder.DefineDynamicAssembly(new AssemblyName { Name = name }, AssemblyBuilderAccess.Run);
  515. #else
  516. return Thread.GetDomain().DefineDynamicAssembly(new AssemblyName { Name = name }, AssemblyBuilderAccess.Run);
  517. #endif
  518. }
  519.  
  520. public static T GetInterfaceProxy<T>()
  521. {
  522. Type typeOfT = typeof(T);
  523.  
  524. if (TypeCache.TryGetValue(typeOfT, out Type k))
  525. {
  526. return (T)Activator.CreateInstance(k);
  527. }
  528. var assemblyBuilder = GetAsmBuilder(typeOfT.Name);
  529.  
  530. var moduleBuilder = assemblyBuilder.DefineDynamicModule("SqlMapperExtensions." + typeOfT.Name); //NOTE: to save, add "asdasd.dll" parameter
  531.  
  532. var interfaceType = typeof(IProxy);
  533. var typeBuilder = moduleBuilder.DefineType(typeOfT.Name + "_" + Guid.NewGuid(),
  534. TypeAttributes.Public | TypeAttributes.Class);
  535. typeBuilder.AddInterfaceImplementation(typeOfT);
  536. typeBuilder.AddInterfaceImplementation(interfaceType);
  537.  
  538. //create our _isDirty field, which implements IProxy
  539. var setIsDirtyMethod = CreateIsDirtyProperty(typeBuilder);
  540.  
  541. // Generate a field for each property, which implements the T
  542. foreach (var property in typeof(T).GetProperties())
  543. {
  544. var isId = property.GetCustomAttributes(true).Any(a => a is KeyAttribute);
  545. CreateProperty<T>(typeBuilder, property.Name, property.PropertyType, setIsDirtyMethod, isId);
  546. }
  547.  
  548. #if NETSTANDARD1_3 || NETSTANDARD2_0
  549. var generatedType = typeBuilder.CreateTypeInfo().AsType();
  550. #else
  551. var generatedType = typeBuilder.CreateType();
  552. #endif
  553.  
  554. TypeCache.Add(typeOfT, generatedType);
  555. return (T)Activator.CreateInstance(generatedType);
  556. }
  557.  
  558. private static MethodInfo CreateIsDirtyProperty(TypeBuilder typeBuilder)
  559. {
  560. var propType = typeof(bool);
  561. var field = typeBuilder.DefineField("_" + nameof(IProxy.IsDirty), propType, FieldAttributes.Private);
  562. var property = typeBuilder.DefineProperty(nameof(IProxy.IsDirty),
  563. System.Reflection.PropertyAttributes.None,
  564. propType,
  565. new[] { propType });
  566.  
  567. const MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.NewSlot | MethodAttributes.SpecialName
  568. | MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.HideBySig;
  569.  
  570. // Define the "get" and "set" accessor methods
  571. var currGetPropMthdBldr = typeBuilder.DefineMethod("get_" + nameof(IProxy.IsDirty),
  572. getSetAttr,
  573. propType,
  574. Type.EmptyTypes);
  575. var currGetIl = currGetPropMthdBldr.GetILGenerator();
  576. currGetIl.Emit(OpCodes.Ldarg_0);
  577. currGetIl.Emit(OpCodes.Ldfld, field);
  578. currGetIl.Emit(OpCodes.Ret);
  579. var currSetPropMthdBldr = typeBuilder.DefineMethod("set_" + nameof(IProxy.IsDirty),
  580. getSetAttr,
  581. null,
  582. new[] { propType });
  583. var currSetIl = currSetPropMthdBldr.GetILGenerator();
  584. currSetIl.Emit(OpCodes.Ldarg_0);
  585. currSetIl.Emit(OpCodes.Ldarg_1);
  586. currSetIl.Emit(OpCodes.Stfld, field);
  587. currSetIl.Emit(OpCodes.Ret);
  588.  
  589. property.SetGetMethod(currGetPropMthdBldr);
  590. property.SetSetMethod(currSetPropMthdBldr);
  591. var getMethod = typeof(IProxy).GetMethod("get_" + nameof(IProxy.IsDirty));
  592. var setMethod = typeof(IProxy).GetMethod("set_" + nameof(IProxy.IsDirty));
  593. typeBuilder.DefineMethodOverride(currGetPropMthdBldr, getMethod);
  594. typeBuilder.DefineMethodOverride(currSetPropMthdBldr, setMethod);
  595.  
  596. return currSetPropMthdBldr;
  597. }
  598.  
  599. private static void CreateProperty<T>(TypeBuilder typeBuilder, string propertyName, Type propType, MethodInfo setIsDirtyMethod, bool isIdentity)
  600. {
  601. //Define the field and the property
  602. var field = typeBuilder.DefineField("_" + propertyName, propType, FieldAttributes.Private);
  603. var property = typeBuilder.DefineProperty(propertyName,
  604. System.Reflection.PropertyAttributes.None,
  605. propType,
  606. new[] { propType });
  607.  
  608. const MethodAttributes getSetAttr = MethodAttributes.Public
  609. | MethodAttributes.Virtual
  610. | MethodAttributes.HideBySig;
  611.  
  612. // Define the "get" and "set" accessor methods
  613. var currGetPropMthdBldr = typeBuilder.DefineMethod("get_" + propertyName,
  614. getSetAttr,
  615. propType,
  616. Type.EmptyTypes);
  617.  
  618. var currGetIl = currGetPropMthdBldr.GetILGenerator();
  619. currGetIl.Emit(OpCodes.Ldarg_0);
  620. currGetIl.Emit(OpCodes.Ldfld, field);
  621. currGetIl.Emit(OpCodes.Ret);
  622.  
  623. var currSetPropMthdBldr = typeBuilder.DefineMethod("set_" + propertyName,
  624. getSetAttr,
  625. null,
  626. new[] { propType });
  627.  
  628. //store value in private field and set the isdirty flag
  629. var currSetIl = currSetPropMthdBldr.GetILGenerator();
  630. currSetIl.Emit(OpCodes.Ldarg_0);
  631. currSetIl.Emit(OpCodes.Ldarg_1);
  632. currSetIl.Emit(OpCodes.Stfld, field);
  633. currSetIl.Emit(OpCodes.Ldarg_0);
  634. currSetIl.Emit(OpCodes.Ldc_I4_1);
  635. currSetIl.Emit(OpCodes.Call, setIsDirtyMethod);
  636. currSetIl.Emit(OpCodes.Ret);
  637.  
  638. //TODO: Should copy all attributes defined by the interface?
  639. if (isIdentity)
  640. {
  641. var keyAttribute = typeof(KeyAttribute);
  642. var myConstructorInfo = keyAttribute.GetConstructor(new Type[] { });
  643. var attributeBuilder = new CustomAttributeBuilder(myConstructorInfo, new object[] { });
  644. property.SetCustomAttribute(attributeBuilder);
  645. }
  646.  
  647. property.SetGetMethod(currGetPropMthdBldr);
  648. property.SetSetMethod(currSetPropMthdBldr);
  649. var getMethod = typeof(T).GetMethod("get_" + propertyName);
  650. var setMethod = typeof(T).GetMethod("set_" + propertyName);
  651. typeBuilder.DefineMethodOverride(currGetPropMthdBldr, getMethod);
  652. typeBuilder.DefineMethodOverride(currSetPropMthdBldr, setMethod);
  653. }
  654. }
  655. }
  656.  
  657. /// <summary>
  658. /// Defines the name of a table to use in Dapper.Contrib commands.
  659. /// </summary>
  660. [AttributeUsage(AttributeTargets.Class)]
  661. public class TableAttribute : Attribute
  662. {
  663. /// <summary>
  664. /// Creates a table mapping to a specific name for Dapper.Contrib commands
  665. /// </summary>
  666. /// <param name="tableName">The name of this table in the database.</param>
  667. public TableAttribute(string tableName)
  668. {
  669. Name = tableName;
  670. }
  671.  
  672. /// <summary>
  673. /// The name of the table in the database
  674. /// </summary>
  675. public string Name { get; set; }
  676. }
  677.  
  678. /// <summary>
  679. /// Specifies that this field is a primary key in the database
  680. /// </summary>
  681. [AttributeUsage(AttributeTargets.Property)]
  682. public class KeyAttribute : Attribute
  683. {
  684. }
  685.  
  686. /// <summary>
  687. /// Specifies that this field is a explicitly set primary key in the database
  688. /// </summary>
  689. [AttributeUsage(AttributeTargets.Property)]
  690. public class ExplicitKeyAttribute : Attribute
  691. {
  692. }
  693.  
  694. /// <summary>
  695. /// Specifies whether a field is writable in the database.
  696. /// </summary>
  697. [AttributeUsage(AttributeTargets.Property)]
  698. public class WriteAttribute : Attribute
  699. {
  700. /// <summary>
  701. /// Specifies whether a field is writable in the database.
  702. /// </summary>
  703. /// <param name="write">Whether a field is writable in the database.</param>
  704. public WriteAttribute(bool write)
  705. {
  706. Write = write;
  707. }
  708.  
  709. /// <summary>
  710. /// Whether a field is writable in the database.
  711. /// </summary>
  712. public bool Write { get; }
  713. }
  714.  
  715. /// <summary>
  716. /// Specifies that this is a computed column.
  717. /// </summary>
  718. [AttributeUsage(AttributeTargets.Property)]
  719. public class ComputedAttribute : Attribute
  720. {
  721. }
  722. internal static class TypeExtensions
  723. {
  724. public static string Name(this Type type) =>
  725. #if NETSTANDARD1_3 || NETCOREAPP1_0
  726. type.GetTypeInfo().Name;
  727. #else
  728. type.Name;
  729. #endif
  730.  
  731. public static bool IsValueType(this Type type) =>
  732. #if NETSTANDARD1_3 || NETCOREAPP1_0
  733. type.GetTypeInfo().IsValueType;
  734. #else
  735. type.IsValueType;
  736. #endif
  737.  
  738. public static bool IsEnum(this Type type) =>
  739. #if NETSTANDARD1_3 || NETCOREAPP1_0
  740. type.GetTypeInfo().IsEnum;
  741. #else
  742. type.IsEnum;
  743. #endif
  744.  
  745. public static bool IsGenericType(this Type type) =>
  746. #if NETSTANDARD1_3 || NETCOREAPP1_0
  747. type.GetTypeInfo().IsGenericType;
  748. #else
  749. type.IsGenericType;
  750. #endif
  751.  
  752. public static bool IsInterface(this Type type) =>
  753. #if NETSTANDARD1_3 || NETCOREAPP1_0
  754. type.GetTypeInfo().IsInterface;
  755. #else
  756. type.IsInterface;
  757. #endif
  758.  
  759. #if NETSTANDARD1_3 || NETCOREAPP1_0
  760. public static IEnumerable<Attribute> GetCustomAttributes(this Type type, bool inherit)
  761. {
  762. return type.GetTypeInfo().GetCustomAttributes(inherit);
  763. }
  764.  
  765. public static TypeCode GetTypeCode(Type type)
  766. {
  767. if (type == null) return TypeCode.Empty;
  768. if (typeCodeLookup.TryGetValue(type, out TypeCode result)) return result;
  769.  
  770. if (type.IsEnum())
  771. {
  772. type = Enum.GetUnderlyingType(type);
  773. if (typeCodeLookup.TryGetValue(type, out result)) return result;
  774. }
  775. return TypeCode.Object;
  776. }
  777.  
  778. private static readonly Dictionary<Type, TypeCode> typeCodeLookup = new Dictionary<Type, TypeCode>
  779. {
  780. [typeof(bool)] = TypeCode.Boolean,
  781. [typeof(byte)] = TypeCode.Byte,
  782. [typeof(char)] = TypeCode.Char,
  783. [typeof(DateTime)] = TypeCode.DateTime,
  784. [typeof(decimal)] = TypeCode.Decimal,
  785. [typeof(double)] = TypeCode.Double,
  786. [typeof(short)] = TypeCode.Int16,
  787. [typeof(int)] = TypeCode.Int32,
  788. [typeof(long)] = TypeCode.Int64,
  789. [typeof(object)] = TypeCode.Object,
  790. [typeof(sbyte)] = TypeCode.SByte,
  791. [typeof(float)] = TypeCode.Single,
  792. [typeof(string)] = TypeCode.String,
  793. [typeof(ushort)] = TypeCode.UInt16,
  794. [typeof(uint)] = TypeCode.UInt32,
  795. [typeof(ulong)] = TypeCode.UInt64,
  796. };
  797. #else
  798. public static TypeCode GetTypeCode(Type type) => Type.GetTypeCode(type);
  799. #endif
  800.  
  801. public static MethodInfo GetPublicInstanceMethod(this Type type, string name, Type[] types)
  802. {
  803. #if NETSTANDARD1_3 || NETCOREAPP1_0
  804. var method = type.GetMethod(name, types);
  805. return (method?.IsPublic == true && !method.IsStatic) ? method : null;
  806. #else
  807. return type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public, null, types, null);
  808. #endif
  809. }
  810. }
  811. }
  812.  
  813. /// <summary>
  814. /// The interface for all Dapper.Contrib database operations
  815. /// Implementing this is each provider's model.
  816. /// </summary>
  817. public partial interface ISqlAdapter
  818. {
  819. /// <summary>
  820. /// Inserts <paramref name="entityToInsert"/> into the database, returning the Id of the row created.
  821. /// </summary>
  822. /// <param name="connection">The connection to use.</param>
  823. /// <param name="transaction">The transaction to use.</param>
  824. /// <param name="commandTimeout">The command timeout to use.</param>
  825. /// <param name="tableName">The table to insert into.</param>
  826. /// <param name="columnList">The columns to set with this insert.</param>
  827. /// <param name="parameterList">The parameters to set for this insert.</param>
  828. /// <param name="keyProperties">The key columns in this table.</param>
  829. /// <param name="entityToInsert">The entity to insert.</param>
  830. /// <returns>The Id of the row created.</returns>
  831. int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert);
  832.  
  833. /// <summary>
  834. /// Adds the name of a column.
  835. /// </summary>
  836. /// <param name="sb">The string builder to append to.</param>
  837. /// <param name="columnName">The column name.</param>
  838. void AppendColumnName(StringBuilder sb, string columnName);
  839. /// <summary>
  840. /// Adds a column equality to a parameter.
  841. /// </summary>
  842. /// <param name="sb">The string builder to append to.</param>
  843. /// <param name="columnName">The column name.</param>
  844. void AppendColumnNameEqualsValue(StringBuilder sb, string columnName);
  845. }
  846.  
  847. /// <summary>
  848. /// The Oracle database adapter.
  849. /// </summary>
  850. public partial class OracleAdapter : ISqlAdapter
  851. {
  852. /// <summary>
  853. /// Inserts <paramref name="entityToInsert"/> into the database, returning the Id of the row created.
  854. /// </summary>
  855. /// <param name="connection">The connection to use.</param>
  856. /// <param name="transaction">The transaction to use.</param>
  857. /// <param name="commandTimeout">The command timeout to use.</param>
  858. /// <param name="tableName">The table to insert into.</param>
  859. /// <param name="columnList">The columns to set with this insert.</param>
  860. /// <param name="parameterList">The parameters to set for this insert.</param>
  861. /// <param name="keyProperties">The key columns in this table.</param>
  862. /// <param name="entityToInsert">The entity to insert.</param>
  863. /// <returns>The Id of the row created.</returns>
  864. public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
  865. {
  866. var keyFirst = keyProperties.First();
  867. var keyName = keyFirst.Name;
  868. var cmd = $"BEGIN INSERT INTO {tableName} ({columnList}) VALUES ({parameterList}) RETURNING {keyName} INTO :ID; END;";//$"BEGIN INSERT INTO {tableName} ({columnList}) VALUES ({parameterList}) RETURNING ID INTO :ID; END;";
  869.  
  870. var multi = connection.QueryMultiple(cmd, entityToInsert, transaction, commandTimeout);
  871. var idKey = multi.Command.Parameters["ID"] as IDataParameter;
  872. if(keyFirst.PropertyType == typeof(int) || keyFirst.PropertyType == typeof(long))
  873. {
  874. return (int)idKey.Value;
  875. }
  876. return ;
  877. }
  878.  
  879. /// <summary>
  880. /// Adds the name of a column.
  881. /// </summary>
  882. /// <param name="sb">The string builder to append to.</param>
  883. /// <param name="columnName">The column name.</param>
  884. public void AppendColumnName(StringBuilder sb, string columnName)
  885. {
  886. sb.AppendFormat("{0}", columnName);
  887. }
  888.  
  889. /// <summary>
  890. /// Adds a column equality to a parameter.
  891. /// </summary>
  892. /// <param name="sb">The string builder to append to.</param>
  893. /// <param name="columnName">The column name.</param>
  894. public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName)
  895. {
  896. sb.AppendFormat("{0} = :{1}", columnName, columnName);
  897. }
  898. }
  899.  
  900. /// <summary>
  901. /// The SQL Server database adapter.
  902. /// </summary>
  903. public partial class SqlServerAdapter : ISqlAdapter
  904. {
  905. /// <summary>
  906. /// Inserts <paramref name="entityToInsert"/> into the database, returning the Id of the row created.
  907. /// </summary>
  908. /// <param name="connection">The connection to use.</param>
  909. /// <param name="transaction">The transaction to use.</param>
  910. /// <param name="commandTimeout">The command timeout to use.</param>
  911. /// <param name="tableName">The table to insert into.</param>
  912. /// <param name="columnList">The columns to set with this insert.</param>
  913. /// <param name="parameterList">The parameters to set for this insert.</param>
  914. /// <param name="keyProperties">The key columns in this table.</param>
  915. /// <param name="entityToInsert">The entity to insert.</param>
  916. /// <returns>The Id of the row created.</returns>
  917. public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
  918. {
  919. var cmd = $"insert into {tableName} ({columnList}) values ({parameterList});select SCOPE_IDENTITY() id";
  920. var multi = connection.QueryMultiple(cmd, entityToInsert, transaction, commandTimeout);
  921.  
  922. var first = multi.Read().FirstOrDefault();
  923. if (first == null || first.id == null) return ;
  924.  
  925. var id = (int)first.id;
  926. var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
  927. if (propertyInfos.Length == ) return id;
  928.  
  929. var idProperty = propertyInfos[];
  930. idProperty.SetValue(entityToInsert, Convert.ChangeType(id, idProperty.PropertyType), null);
  931.  
  932. return id;
  933. }
  934.  
  935. /// <summary>
  936. /// Adds the name of a column.
  937. /// </summary>
  938. /// <param name="sb">The string builder to append to.</param>
  939. /// <param name="columnName">The column name.</param>
  940. public void AppendColumnName(StringBuilder sb, string columnName)
  941. {
  942. sb.AppendFormat("[{0}]", columnName);
  943. }
  944.  
  945. /// <summary>
  946. /// Adds a column equality to a parameter.
  947. /// </summary>
  948. /// <param name="sb">The string builder to append to.</param>
  949. /// <param name="columnName">The column name.</param>
  950. public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName)
  951. {
  952. sb.AppendFormat("[{0}] = @{1}", columnName, columnName);
  953. }
  954. }
  955.  
  956. /// <summary>
  957. /// The SQL Server Compact Edition database adapter.
  958. /// </summary>
  959. public partial class SqlCeServerAdapter : ISqlAdapter
  960. {
  961. /// <summary>
  962. /// Inserts <paramref name="entityToInsert"/> into the database, returning the Id of the row created.
  963. /// </summary>
  964. /// <param name="connection">The connection to use.</param>
  965. /// <param name="transaction">The transaction to use.</param>
  966. /// <param name="commandTimeout">The command timeout to use.</param>
  967. /// <param name="tableName">The table to insert into.</param>
  968. /// <param name="columnList">The columns to set with this insert.</param>
  969. /// <param name="parameterList">The parameters to set for this insert.</param>
  970. /// <param name="keyProperties">The key columns in this table.</param>
  971. /// <param name="entityToInsert">The entity to insert.</param>
  972. /// <returns>The Id of the row created.</returns>
  973. public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
  974. {
  975. var cmd = $"insert into {tableName} ({columnList}) values ({parameterList})";
  976. connection.Execute(cmd, entityToInsert, transaction, commandTimeout);
  977. var r = connection.Query("select @@IDENTITY id", transaction: transaction, commandTimeout: commandTimeout).ToList();
  978.  
  979. if (r[].id == null) return ;
  980. var id = (int)r[].id;
  981.  
  982. var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
  983. if (propertyInfos.Length == ) return id;
  984.  
  985. var idProperty = propertyInfos[];
  986. idProperty.SetValue(entityToInsert, Convert.ChangeType(id, idProperty.PropertyType), null);
  987.  
  988. return id;
  989. }
  990.  
  991. /// <summary>
  992. /// Adds the name of a column.
  993. /// </summary>
  994. /// <param name="sb">The string builder to append to.</param>
  995. /// <param name="columnName">The column name.</param>
  996. public void AppendColumnName(StringBuilder sb, string columnName)
  997. {
  998. sb.AppendFormat("[{0}]", columnName);
  999. }
  1000.  
  1001. /// <summary>
  1002. /// Adds a column equality to a parameter.
  1003. /// </summary>
  1004. /// <param name="sb">The string builder to append to.</param>
  1005. /// <param name="columnName">The column name.</param>
  1006. public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName)
  1007. {
  1008. sb.AppendFormat("[{0}] = @{1}", columnName, columnName);
  1009. }
  1010. }
  1011.  
  1012. /// <summary>
  1013. /// The MySQL database adapter.
  1014. /// </summary>
  1015. public partial class MySqlAdapter : ISqlAdapter
  1016. {
  1017. /// <summary>
  1018. /// Inserts <paramref name="entityToInsert"/> into the database, returning the Id of the row created.
  1019. /// </summary>
  1020. /// <param name="connection">The connection to use.</param>
  1021. /// <param name="transaction">The transaction to use.</param>
  1022. /// <param name="commandTimeout">The command timeout to use.</param>
  1023. /// <param name="tableName">The table to insert into.</param>
  1024. /// <param name="columnList">The columns to set with this insert.</param>
  1025. /// <param name="parameterList">The parameters to set for this insert.</param>
  1026. /// <param name="keyProperties">The key columns in this table.</param>
  1027. /// <param name="entityToInsert">The entity to insert.</param>
  1028. /// <returns>The Id of the row created.</returns>
  1029. public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
  1030. {
  1031. var cmd = $"insert into {tableName} ({columnList}) values ({parameterList})";
  1032. connection.Execute(cmd, entityToInsert, transaction, commandTimeout);
  1033. var r = connection.Query("Select LAST_INSERT_ID() id", transaction: transaction, commandTimeout: commandTimeout);
  1034.  
  1035. var id = r.First().id;
  1036. if (id == null) return ;
  1037. var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
  1038. if (propertyInfos.Length == ) return Convert.ToInt32(id);
  1039.  
  1040. var idp = propertyInfos[];
  1041. idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null);
  1042.  
  1043. return Convert.ToInt32(id);
  1044. }
  1045.  
  1046. /// <summary>
  1047. /// Adds the name of a column.
  1048. /// </summary>
  1049. /// <param name="sb">The string builder to append to.</param>
  1050. /// <param name="columnName">The column name.</param>
  1051. public void AppendColumnName(StringBuilder sb, string columnName)
  1052. {
  1053. sb.AppendFormat("`{0}`", columnName);
  1054. }
  1055.  
  1056. /// <summary>
  1057. /// Adds a column equality to a parameter.
  1058. /// </summary>
  1059. /// <param name="sb">The string builder to append to.</param>
  1060. /// <param name="columnName">The column name.</param>
  1061. public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName)
  1062. {
  1063. sb.AppendFormat("`{0}` = @{1}", columnName, columnName);
  1064. }
  1065. }
  1066.  
  1067. /// <summary>
  1068. /// The Postgres database adapter.
  1069. /// </summary>
  1070. public partial class PostgresAdapter : ISqlAdapter
  1071. {
  1072. /// <summary>
  1073. /// Inserts <paramref name="entityToInsert"/> into the database, returning the Id of the row created.
  1074. /// </summary>
  1075. /// <param name="connection">The connection to use.</param>
  1076. /// <param name="transaction">The transaction to use.</param>
  1077. /// <param name="commandTimeout">The command timeout to use.</param>
  1078. /// <param name="tableName">The table to insert into.</param>
  1079. /// <param name="columnList">The columns to set with this insert.</param>
  1080. /// <param name="parameterList">The parameters to set for this insert.</param>
  1081. /// <param name="keyProperties">The key columns in this table.</param>
  1082. /// <param name="entityToInsert">The entity to insert.</param>
  1083. /// <returns>The Id of the row created.</returns>
  1084. public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
  1085. {
  1086. var sb = new StringBuilder();
  1087. sb.AppendFormat("insert into {0} ({1}) values ({2})", tableName, columnList, parameterList);
  1088.  
  1089. // If no primary key then safe to assume a join table with not too much data to return
  1090. var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
  1091. if (propertyInfos.Length == )
  1092. {
  1093. sb.Append(" RETURNING *");
  1094. }
  1095. else
  1096. {
  1097. sb.Append(" RETURNING ");
  1098. var first = true;
  1099. foreach (var property in propertyInfos)
  1100. {
  1101. if (!first)
  1102. sb.Append(", ");
  1103. first = false;
  1104. sb.Append(property.Name);
  1105. }
  1106. }
  1107.  
  1108. var results = connection.Query(sb.ToString(), entityToInsert, transaction, commandTimeout: commandTimeout).ToList();
  1109.  
  1110. // Return the key by assinging the corresponding property in the object - by product is that it supports compound primary keys
  1111. var id = ;
  1112. foreach (var p in propertyInfos)
  1113. {
  1114. var value = ((IDictionary<string, object>)results[])[p.Name.ToLower()];
  1115. p.SetValue(entityToInsert, value, null);
  1116. if (id == )
  1117. id = Convert.ToInt32(value);
  1118. }
  1119. return id;
  1120. }
  1121.  
  1122. /// <summary>
  1123. /// Adds the name of a column.
  1124. /// </summary>
  1125. /// <param name="sb">The string builder to append to.</param>
  1126. /// <param name="columnName">The column name.</param>
  1127. public void AppendColumnName(StringBuilder sb, string columnName)
  1128. {
  1129. sb.AppendFormat("\"{0}\"", columnName);
  1130. }
  1131.  
  1132. /// <summary>
  1133. /// Adds a column equality to a parameter.
  1134. /// </summary>
  1135. /// <param name="sb">The string builder to append to.</param>
  1136. /// <param name="columnName">The column name.</param>
  1137. public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName)
  1138. {
  1139. sb.AppendFormat("\"{0}\" = @{1}", columnName, columnName);
  1140. }
  1141. }
  1142.  
  1143. /// <summary>
  1144. /// The SQLite database adapter.
  1145. /// </summary>
  1146. public partial class SQLiteAdapter : ISqlAdapter
  1147. {
  1148. /// <summary>
  1149. /// Inserts <paramref name="entityToInsert"/> into the database, returning the Id of the row created.
  1150. /// </summary>
  1151. /// <param name="connection">The connection to use.</param>
  1152. /// <param name="transaction">The transaction to use.</param>
  1153. /// <param name="commandTimeout">The command timeout to use.</param>
  1154. /// <param name="tableName">The table to insert into.</param>
  1155. /// <param name="columnList">The columns to set with this insert.</param>
  1156. /// <param name="parameterList">The parameters to set for this insert.</param>
  1157. /// <param name="keyProperties">The key columns in this table.</param>
  1158. /// <param name="entityToInsert">The entity to insert.</param>
  1159. /// <returns>The Id of the row created.</returns>
  1160. public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
  1161. {
  1162. var cmd = $"INSERT INTO {tableName} ({columnList}) VALUES ({parameterList}); SELECT last_insert_rowid() id";
  1163. var multi = connection.QueryMultiple(cmd, entityToInsert, transaction, commandTimeout);
  1164.  
  1165. var id = (int)multi.Read().First().id;
  1166. var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
  1167. if (propertyInfos.Length == ) return id;
  1168.  
  1169. var idProperty = propertyInfos[];
  1170. idProperty.SetValue(entityToInsert, Convert.ChangeType(id, idProperty.PropertyType), null);
  1171.  
  1172. return id;
  1173. }
  1174.  
  1175. /// <summary>
  1176. /// Adds the name of a column.
  1177. /// </summary>
  1178. /// <param name="sb">The string builder to append to.</param>
  1179. /// <param name="columnName">The column name.</param>
  1180. public void AppendColumnName(StringBuilder sb, string columnName)
  1181. {
  1182. sb.AppendFormat("\"{0}\"", columnName);
  1183. }
  1184.  
  1185. /// <summary>
  1186. /// Adds a column equality to a parameter.
  1187. /// </summary>
  1188. /// <param name="sb">The string builder to append to.</param>
  1189. /// <param name="columnName">The column name.</param>
  1190. public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName)
  1191. {
  1192. sb.AppendFormat("\"{0}\" = @{1}", columnName, columnName);
  1193. }
  1194. }
  1195.  
  1196. /// <summary>
  1197. /// The Firebase SQL adapeter.
  1198. /// </summary>
  1199. public partial class FbAdapter : ISqlAdapter
  1200. {
  1201. /// <summary>
  1202. /// Inserts <paramref name="entityToInsert"/> into the database, returning the Id of the row created.
  1203. /// </summary>
  1204. /// <param name="connection">The connection to use.</param>
  1205. /// <param name="transaction">The transaction to use.</param>
  1206. /// <param name="commandTimeout">The command timeout to use.</param>
  1207. /// <param name="tableName">The table to insert into.</param>
  1208. /// <param name="columnList">The columns to set with this insert.</param>
  1209. /// <param name="parameterList">The parameters to set for this insert.</param>
  1210. /// <param name="keyProperties">The key columns in this table.</param>
  1211. /// <param name="entityToInsert">The entity to insert.</param>
  1212. /// <returns>The Id of the row created.</returns>
  1213. public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
  1214. {
  1215. var cmd = $"insert into {tableName} ({columnList}) values ({parameterList})";
  1216. connection.Execute(cmd, entityToInsert, transaction, commandTimeout);
  1217.  
  1218. var propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
  1219. var keyName = propertyInfos[].Name;
  1220. var r = connection.Query($"SELECT FIRST 1 {keyName} ID FROM {tableName} ORDER BY {keyName} DESC", transaction: transaction, commandTimeout: commandTimeout);
  1221.  
  1222. var id = r.First().ID;
  1223. if (id == null) return ;
  1224. if (propertyInfos.Length == ) return Convert.ToInt32(id);
  1225.  
  1226. var idp = propertyInfos[];
  1227. idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null);
  1228.  
  1229. return Convert.ToInt32(id);
  1230. }
  1231.  
  1232. /// <summary>
  1233. /// Adds the name of a column.
  1234. /// </summary>
  1235. /// <param name="sb">The string builder to append to.</param>
  1236. /// <param name="columnName">The column name.</param>
  1237. public void AppendColumnName(StringBuilder sb, string columnName)
  1238. {
  1239. sb.AppendFormat("{0}", columnName);
  1240. }
  1241.  
  1242. /// <summary>
  1243. /// Adds a column equality to a parameter.
  1244. /// </summary>
  1245. /// <param name="sb">The string builder to append to.</param>
  1246. /// <param name="columnName">The column name.</param>
  1247. public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName)
  1248. {
  1249. sb.AppendFormat("{0} = @{1}", columnName, columnName);
  1250. }
  1251. }
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Dapper; namespace Dapper.Contrib.Extensions
{
public static partial class SqlMapperExtensions
{
/// <summary>
/// Returns a single entity by a single id from table "Ts" asynchronously using .NET 4.5 Task. T must be of interface type.
/// Id must be marked with [Key] attribute.
/// Created entity is tracked/intercepted for changes and used by the Update() extension.
/// </summary>
/// <typeparam name="T">Interface type to create and populate</typeparam>
/// <param name="connection">Open SqlConnection</param>
/// <param name="id">Id of the entity to get, must be marked with [Key] attribute</param>
/// <param name="transaction">The transaction to run under, null (the default) if none</param>
/// <param name="commandTimeout">Number of seconds before command execution timeout</param>
/// <returns>Entity of T</returns>
public static async Task<T> GetAsync<T>(this IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{
var type = typeof(T);
if (!GetQueries.TryGetValue(type.TypeHandle, out string sql))
{
var key = GetSingleKey<T>(nameof(GetAsync));
var name = GetTableName(type); sql = $"SELECT * FROM {name} WHERE {key.Name} = :id";
GetQueries[type.TypeHandle] = sql;
} var dynParms = new DynamicParameters();
dynParms.Add(":id", id); if (!type.IsInterface())
return (await connection.QueryAsync<T>(sql, dynParms, transaction, commandTimeout).ConfigureAwait(false)).FirstOrDefault(); var res = (await connection.QueryAsync<dynamic>(sql, dynParms).ConfigureAwait(false)).FirstOrDefault() as IDictionary<string, object>; if (res == null)
return null; var obj = ProxyGenerator.GetInterfaceProxy<T>(); foreach (var property in TypePropertiesCache(type))
{
var val = res[property.Name];
property.SetValue(obj, Convert.ChangeType(val, property.PropertyType), null);
} ((IProxy)obj).IsDirty = false; //reset change tracking and return return obj;
} /// <summary>
/// Returns a list of entites from table "Ts".
/// Id of T must be marked with [Key] attribute.
/// Entities created from interfaces are tracked/intercepted for changes and used by the Update() extension
/// for optimal performance.
/// </summary>
/// <typeparam name="T">Interface or type to create and populate</typeparam>
/// <param name="connection">Open SqlConnection</param>
/// <param name="transaction">The transaction to run under, null (the default) if none</param>
/// <param name="commandTimeout">Number of seconds before command execution timeout</param>
/// <returns>Entity of T</returns>
public static Task<IEnumerable<T>> GetAllAsync<T>(this IDbConnection connection, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{
var type = typeof(T);
var cacheType = typeof(List<T>); if (!GetQueries.TryGetValue(cacheType.TypeHandle, out string sql))
{
GetSingleKey<T>(nameof(GetAll));
var name = GetTableName(type); sql = "SELECT * FROM " + name;
GetQueries[cacheType.TypeHandle] = sql;
} if (!type.IsInterface())
{
return connection.QueryAsync<T>(sql, null, transaction, commandTimeout);
}
return GetAllAsyncImpl<T>(connection, transaction, commandTimeout, sql, type);
} private static async Task<IEnumerable<T>> GetAllAsyncImpl<T>(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string sql, Type type) where T : class
{
var result = await connection.QueryAsync(sql).ConfigureAwait(false);
var list = new List<T>();
foreach (IDictionary<string, object> res in result)
{
var obj = ProxyGenerator.GetInterfaceProxy<T>();
foreach (var property in TypePropertiesCache(type))
{
var val = res[property.Name];
property.SetValue(obj, Convert.ChangeType(val, property.PropertyType), null);
}
((IProxy)obj).IsDirty = false; //reset change tracking and return
list.Add(obj);
}
return list;
} /// <summary>
/// Inserts an entity into table "Ts" asynchronously using .NET 4.5 Task and returns identity id.
/// </summary>
/// <typeparam name="T">The type being inserted.</typeparam>
/// <param name="connection">Open SqlConnection</param>
/// <param name="entityToInsert">Entity to insert</param>
/// <param name="transaction">The transaction to run under, null (the default) if none</param>
/// <param name="commandTimeout">Number of seconds before command execution timeout</param>
/// <param name="sqlAdapter">The specific ISqlAdapter to use, auto-detected based on connection if null</param>
/// <returns>Identity of inserted entity</returns>
public static Task<int> InsertAsync<T>(this IDbConnection connection, T entityToInsert, IDbTransaction transaction = null,
int? commandTimeout = null, ISqlAdapter sqlAdapter = null) where T : class
{
var type = typeof(T);
sqlAdapter = sqlAdapter ?? GetFormatter(connection); var isList = false;
if (type.IsArray)
{
isList = true;
type = type.GetElementType();
}
else if (type.IsGenericType())
{
isList = true;
type = type.GetGenericArguments()[];
} var name = GetTableName(type);
var sbColumnList = new StringBuilder(null);
var allProperties = TypePropertiesCache(type);
var keyProperties = KeyPropertiesCache(type);
var computedProperties = ComputedPropertiesCache(type);
var allPropertiesExceptKeyAndComputed = allProperties.Except(keyProperties.Union(computedProperties)).ToList(); for (var i = ; i < allPropertiesExceptKeyAndComputed.Count; i++)
{
var property = allPropertiesExceptKeyAndComputed[i];
sqlAdapter.AppendColumnName(sbColumnList, property.Name);
if (i < allPropertiesExceptKeyAndComputed.Count - )
sbColumnList.Append(", ");
} var sbParameterList = new StringBuilder(null);
for (var i = ; i < allPropertiesExceptKeyAndComputed.Count; i++)
{
var property = allPropertiesExceptKeyAndComputed[i];
sbParameterList.AppendFormat(":{0}", property.Name);
if (i < allPropertiesExceptKeyAndComputed.Count - )
sbParameterList.Append(", ");
} if (!isList) //single entity
{
return sqlAdapter.InsertAsync(connection, transaction, commandTimeout, name, sbColumnList.ToString(),
sbParameterList.ToString(), keyProperties, entityToInsert);
} //insert list of entities
var cmd = $"INSERT INTO {name} ({sbColumnList}) values ({sbParameterList})";
return connection.ExecuteAsync(cmd, entityToInsert, transaction, commandTimeout);
} /// <summary>
/// Updates entity in table "Ts" asynchronously using .NET 4.5 Task, checks if the entity is modified if the entity is tracked by the Get() extension.
/// </summary>
/// <typeparam name="T">Type to be updated</typeparam>
/// <param name="connection">Open SqlConnection</param>
/// <param name="entityToUpdate">Entity to be updated</param>
/// <param name="transaction">The transaction to run under, null (the default) if none</param>
/// <param name="commandTimeout">Number of seconds before command execution timeout</param>
/// <returns>true if updated, false if not found or not modified (tracked entities)</returns>
public static async Task<bool> UpdateAsync<T>(this IDbConnection connection, T entityToUpdate, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{
if ((entityToUpdate is IProxy proxy) && !proxy.IsDirty)
{
return false;
} var type = typeof(T); if (type.IsArray)
{
type = type.GetElementType();
}
else if (type.IsGenericType())
{
type = type.GetGenericArguments()[];
} var keyProperties = KeyPropertiesCache(type);
var explicitKeyProperties = ExplicitKeyPropertiesCache(type);
if (keyProperties.Count == && explicitKeyProperties.Count == )
throw new ArgumentException("Entity must have at least one [Key] or [ExplicitKey] property"); var name = GetTableName(type); var sb = new StringBuilder();
sb.AppendFormat("UPDATE {0} SET ", name); var allProperties = TypePropertiesCache(type);
keyProperties.AddRange(explicitKeyProperties);
var computedProperties = ComputedPropertiesCache(type);
var nonIdProps = allProperties.Except(keyProperties.Union(computedProperties)).ToList(); var adapter = GetFormatter(connection); for (var i = ; i < nonIdProps.Count; i++)
{
var property = nonIdProps[i];
adapter.AppendColumnNameEqualsValue(sb, property.Name);
if (i < nonIdProps.Count - )
sb.AppendFormat(", ");
}
sb.Append(" WHERE ");
for (var i = ; i < keyProperties.Count; i++)
{
var property = keyProperties[i];
adapter.AppendColumnNameEqualsValue(sb, property.Name);
if (i < keyProperties.Count - )
sb.AppendFormat(" AND ");
}
var updated = await connection.ExecuteAsync(sb.ToString(), entityToUpdate, commandTimeout: commandTimeout, transaction: transaction).ConfigureAwait(false);
return updated > ;
} /// <summary>
/// Delete entity in table "Ts" asynchronously using .NET 4.5 Task.
/// </summary>
/// <typeparam name="T">Type of entity</typeparam>
/// <param name="connection">Open SqlConnection</param>
/// <param name="entityToDelete">Entity to delete</param>
/// <param name="transaction">The transaction to run under, null (the default) if none</param>
/// <param name="commandTimeout">Number of seconds before command execution timeout</param>
/// <returns>true if deleted, false if not found</returns>
public static async Task<bool> DeleteAsync<T>(this IDbConnection connection, T entityToDelete, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{
if (entityToDelete == null)
throw new ArgumentException("Cannot Delete null Object", nameof(entityToDelete)); var type = typeof(T); if (type.IsArray)
{
type = type.GetElementType();
}
else if (type.IsGenericType())
{
type = type.GetGenericArguments()[];
} var keyProperties = KeyPropertiesCache(type);
var explicitKeyProperties = ExplicitKeyPropertiesCache(type);
if (keyProperties.Count == && explicitKeyProperties.Count == )
throw new ArgumentException("Entity must have at least one [Key] or [ExplicitKey] property"); var name = GetTableName(type);
keyProperties.AddRange(explicitKeyProperties); var sb = new StringBuilder();
sb.AppendFormat("DELETE FROM {0} WHERE ", name); for (var i = ; i < keyProperties.Count; i++)
{
var property = keyProperties[i];
sb.AppendFormat("{0} = :{1}", property.Name, property.Name);
if (i < keyProperties.Count - )
sb.AppendFormat(" AND ");
}
var deleted = await connection.ExecuteAsync(sb.ToString(), entityToDelete, transaction, commandTimeout).ConfigureAwait(false);
return deleted > ;
} /// <summary>
/// Delete all entities in the table related to the type T asynchronously using .NET 4.5 Task.
/// </summary>
/// <typeparam name="T">Type of entity</typeparam>
/// <param name="connection">Open SqlConnection</param>
/// <param name="transaction">The transaction to run under, null (the default) if none</param>
/// <param name="commandTimeout">Number of seconds before command execution timeout</param>
/// <returns>true if deleted, false if none found</returns>
public static async Task<bool> DeleteAllAsync<T>(this IDbConnection connection, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{
var type = typeof(T);
var statement = "DELETE FROM " + GetTableName(type);
var deleted = await connection.ExecuteAsync(statement, null, transaction, commandTimeout).ConfigureAwait(false);
return deleted > ;
}
}
} public partial interface ISqlAdapter
{
/// <summary>
/// Inserts <paramref name="entityToInsert"/> into the database, returning the Id of the row created.
/// </summary>
/// <param name="connection">The connection to use.</param>
/// <param name="transaction">The transaction to use.</param>
/// <param name="commandTimeout">The command timeout to use.</param>
/// <param name="tableName">The table to insert into.</param>
/// <param name="columnList">The columns to set with this insert.</param>
/// <param name="parameterList">The parameters to set for this insert.</param>
/// <param name="keyProperties">The key columns in this table.</param>
/// <param name="entityToInsert">The entity to insert.</param>
/// <returns>The Id of the row created.</returns>
Task<int> InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert);
} public partial class OracleAdapter
{
/// <summary>
/// Inserts <paramref name="entityToInsert"/> into the database, returning the Id of the row created.
/// </summary>
/// <param name="connection">The connection to use.</param>
/// <param name="transaction">The transaction to use.</param>
/// <param name="commandTimeout">The command timeout to use.</param>
/// <param name="tableName">The table to insert into.</param>
/// <param name="columnList">The columns to set with this insert.</param>
/// <param name="parameterList">The parameters to set for this insert.</param>
/// <param name="keyProperties">The key columns in this table.</param>
/// <param name="entityToInsert">The entity to insert.</param>
/// <returns>The Id of the row created.</returns>
public async Task<int> InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
{
var keyFirst = keyProperties.First();
var keyName = keyFirst.Name;
var cmd = $"BEGIN INSERT INTO {tableName} ({columnList}) VALUES ({parameterList}) RETURNING {keyName} INTO :ID; END;";//$"BEGIN INSERT INTO {tableName} ({columnList}) VALUES ({parameterList}) RETURNING ID INTO :ID; END;"; var multi = await connection.QueryMultipleAsync(cmd, entityToInsert, transaction, commandTimeout);
var idKey = multi.Command.Parameters["ID"] as IDataParameter;
if (keyFirst.PropertyType == typeof(int) || keyFirst.PropertyType == typeof(long))
{
return (int)idKey.Value;
}
return ;
}
}
public partial class SqlServerAdapter
{
/// <summary>
/// Inserts <paramref name="entityToInsert"/> into the database, returning the Id of the row created.
/// </summary>
/// <param name="connection">The connection to use.</param>
/// <param name="transaction">The transaction to use.</param>
/// <param name="commandTimeout">The command timeout to use.</param>
/// <param name="tableName">The table to insert into.</param>
/// <param name="columnList">The columns to set with this insert.</param>
/// <param name="parameterList">The parameters to set for this insert.</param>
/// <param name="keyProperties">The key columns in this table.</param>
/// <param name="entityToInsert">The entity to insert.</param>
/// <returns>The Id of the row created.</returns>
public async Task<int> InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
{
var cmd = $"INSERT INTO {tableName} ({columnList}) values ({parameterList}); SELECT SCOPE_IDENTITY() id";
var multi = await connection.QueryMultipleAsync(cmd, entityToInsert, transaction, commandTimeout).ConfigureAwait(false); var first = multi.Read().FirstOrDefault();
if (first == null || first.id == null) return ; var id = (int)first.id;
var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
if (pi.Length == ) return id; var idp = pi[];
idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); return id;
}
} public partial class MySqlAdapter
{
/// <summary>
/// Inserts <paramref name="entityToInsert"/> into the database, returning the Id of the row created.
/// </summary>
/// <param name="connection">The connection to use.</param>
/// <param name="transaction">The transaction to use.</param>
/// <param name="commandTimeout">The command timeout to use.</param>
/// <param name="tableName">The table to insert into.</param>
/// <param name="columnList">The columns to set with this insert.</param>
/// <param name="parameterList">The parameters to set for this insert.</param>
/// <param name="keyProperties">The key columns in this table.</param>
/// <param name="entityToInsert">The entity to insert.</param>
/// <returns>The Id of the row created.</returns>
public async Task<int> InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName,
string columnList, string parameterList, IEnumerable<PropertyInfo> keyProperties, object entityToInsert)
{
var cmd = $"INSERT INTO {tableName} ({columnList}) VALUES ({parameterList})";
await connection.ExecuteAsync(cmd, entityToInsert, transaction, commandTimeout).ConfigureAwait(false);
var r = await connection.QueryAsync<dynamic>("SELECT LAST_INSERT_ID() id", transaction: transaction, commandTimeout: commandTimeout).ConfigureAwait(false); var id = r.First().id;
if (id == null) return ;
var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray();
if (pi.Length == ) return Convert.ToInt32(id); var idp = pi[];
idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); return Convert.ToInt32(id);
}
} }

Dapper 封装oracle底层访问数据库的更多相关文章

  1. ABP框架用Dapper实现通过SQL访问数据库

    ABP的框架(2) - 访问数据库   为了防止不提供原网址的转载,特在这里加上原文链接:http://www.cnblogs.com/skabyy/p/7517397.html 本篇我们实现数据库的 ...

  2. 免安装oracle驱动访问数据库

    try { string connStr = "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.110.110)( ...

  3. NET在64位系統使用32位oracle客户端访问数据库

    客户在win7 64位系统中安装32位的ora客户端,NET 安装后连线数据库 引发BadImageFomatException. 按客户机安装64位ora客户端也不现实,可能会影响其他应用的正常使用 ...

  4. 手工搭建基于ABP的框架(2) - 访问数据库

    为了防止不提供原网址的转载,特在这里加上原文链接: http://www.cnblogs.com/skabyy/p/7517397.html 本篇我们实现数据库的访问.我们将实现两种数据库访问方法来访 ...

  5. 对比传统方式访问数据库和SpringData访问数据库

    我们在写代码的时候应该一边写一边测试,这样的话可以尽快的找到错误,在代码写多了之后去找错误的话不容易给错误定位 传统方式访问数据库 1:创建一个Maven web项目 2:修改pom.xml为以下内容 ...

  6. 使用Spring.net中对Ado.net的抽象封装来访问数据库

    使用Spring.net中对Ado.net的抽象封装来访问数据库     Spring.NET是一个应用程序框架,其目的是协助开发人员创建企业级的.NET应用程序.它提供了很多方面的功能,比如依赖注入 ...

  7. oracle 事务简介,锁的概念,java访问数据库注意事项

    java链接oracle和连接其他数据库一样有两种方式:1 桥接 jdbc-obdc2 jbdc insert语句一次插入大量数据 insert into table (列1,列2,列3) selec ...

  8. .Net程序员学用Oracle系列(16):访问数据库(ODP.NET)

    1..Net for Oracle 常见数据库驱动 1.1.微软提供的驱动 1.2.甲骨文提供的驱动 1.3.其它厂商提供的驱动 2.ODP.NET 常见问题分析 2.1.参数化问题 2.2.方法调用 ...

  9. Winform 利用 Oracle.ManagedDataAccess访问Oracle数据库

    Winform 利用 Oracle.ManagedDataAccess访问Oracle数据库时出现以下错误: Message = "每个配置文件中只允许存在一个 <configSect ...

随机推荐

  1. Redis代码——Python篇

    需要安装的库:redis import redis # 连接数据库 r = redis.StrictRedis(host="localhost", port=6379, passw ...

  2. 20175204 张湲祯 2018-2019-2《Java程序设计》2

    20175204 张湲祯 2018-2019-2<Java程序设计>2 必做课下作业MyCP 要求 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能,要求MyCP ...

  3. Matlab imshow, image, imagesc 三者详细分析

    1.显示RGB图像 相同点:这三个函数都是把m*n*3的矩阵中的数值当做RGB值来显示的. 区别:imshow将图像以原始尺寸显示,image和imagesc则会对图像进行适当的缩放(显示出来的尺寸大 ...

  4. mui 记录

    1.轮播添加无限循环 需要在 .mui-slider-group节点上增加.mui-slider-loop类 2.web移动端侧滑与滑动同时存在 参考https://segmentfault.com/ ...

  5. GDOI2019游记

    只是提前开坑啊,CCF不要禁我赛啊QwQ 虽然才初三,不能进省队,但还是要拼一把,至少不能垫底吧. NTF和CDW两位初二巨佬都在四川省选拿了非正式选手Rank3,4,我还有什么理由去摸鱼? Day\ ...

  6. 树链剖分——模板题hdu3966

    #include<bits/stdc++.h> using namespace std; #define ll long long #define maxn 50005 ]; int he ...

  7. SpringBoot 整合Dubbo

    RPC框架可参考:https://blog.csdn.net/top_code/article/details/54615853 整合可参考:https://www.dalaoyang.cn/arti ...

  8. 2018-2019-2 网络对抗技术 20165314 Exp3 免杀原理与实践

    免杀原理与实践说明 一.实验说明 任务一:正确使用msf编码器,msfvenom生成如jar之类的其他文件,veil-evasion,自己利用shellcode编程等免杀工具或技巧:(1.5分) 任务 ...

  9. 末学者笔记--Centos7系统部署cobbler批量安装系统

      [前言]: cobbler是一个可以实现批量安装系统的Linux应用程序.它有别于pxe+kickstart,cobbler可以实现同个服务器批量安装不同操作系统版本. 系统环境准备及其下载cob ...

  10. 关于DataTable 判断 列名是否存在的方法中英文符合不区分?

    最近系统出现一个错误,排查了很久,发现判断DataTable 列名是否存在时,发现一个坑,居然不会区分中英文符合. 有谁知道其中的原理?先记录一下,免得以后忘记这个天坑. 一. 先初始化一个DataT ...