Advertisement
Guest User

Untitled

a guest
Oct 31st, 2014
232
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 20.28 KB | None | 0 0
  1. public interface IRepositoryFiltered<TObject> where TObject : class
  2. {
  3. int Count { get; }
  4.  
  5. /// <summary>
  6. /// Gets all filtered objects from database
  7. /// </summary>
  8. TObject[] Get();
  9.  
  10. TObject FirstOrDefault();
  11.  
  12. IRepositoryOrdered<TObject> OrderByDescending<TKey>(Expression<Func<TObject, TKey>> orderBy) where TKey : IComparable;
  13.  
  14. IRepositoryOrdered<TObject> OrderBy<TKey>(Expression<Func<TObject, TKey>> orderBy) where TKey : IComparable;
  15.  
  16. int Sum(Expression<Func<TObject, int?>> selector);
  17.  
  18. IQueryable<IGrouping<TKey, TObject>> GroupBy<TKey>(Expression<Func<TObject, TKey>> orderBy);
  19. }
  20.  
  21. private static void SetupMany<T>(this Mock<IRepository<T>> mock, IEnumerable<T> collection) where T : class
  22. {
  23. mock
  24. .Setup(x => x.GetMany(It.IsAny<Expression<Func<T, bool>>>()))
  25. .Returns<Expression<Func<T, bool>>>(expr => collection.Where(expr.Compile()));
  26. }
  27.  
  28. using System;
  29. using System.Collections.Generic;
  30. using System.Data;
  31. using System.Data.Common;
  32. using System.Data.Entity;
  33. using System.Data.Entity.Infrastructure;
  34. using System.Data.SqlClient;
  35. using System.Linq;
  36. using System.Linq.Expressions;
  37. using System.Reflection;
  38. using System.Text;
  39. using System.Text.RegularExpressions;
  40. using ExtensionMethods;
  41.  
  42.  
  43. namespace MyRepository
  44. {
  45. public class Repository<TObject> : AbstractRepository<TObject>,
  46. IRepository<TObject>
  47. , IRepositoryInclude<TObject>
  48. , IRepositoryFiltered<TObject>
  49. , IRepositoryOrdered<TObject>
  50. where TObject : class
  51. {
  52. private readonly IConnectionFactory _connectionFactory;
  53. private readonly IUnitOfWork _unitOfWork;
  54.  
  55.  
  56. public Repository(IConnectionFactory connection, IUnitOfWork unitOfWork)
  57. {
  58. _connectionFactory = connection;
  59. _unitOfWork = unitOfWork;
  60. }
  61.  
  62. protected MWMS_NewWarehouseContext Context
  63. {
  64. get { return _connectionFactory.Get(); }
  65. }
  66.  
  67. protected override IQueryable<TObject> QueryableDbSet
  68. {
  69. get { return DbSet.AsQueryable(); }
  70. }
  71.  
  72. protected DbSet<TObject> DbSet
  73. {
  74. get
  75. {
  76. ConfigureConnection();
  77. return Context.Set<TObject>();
  78. }
  79. }
  80.  
  81. private string TableName
  82. {
  83. get
  84. {
  85. string sql = Context.Set<TObject>().ToString();
  86. var regex = new Regex(@"FROMs+(?<table>.+)s+AS");
  87. Match match = regex.Match(sql);
  88.  
  89. string table = match.Groups["table"].Value;
  90. return table;
  91. }
  92. }
  93.  
  94. protected override IEnumerable<PropertyInfo> ColumnProperties
  95. {
  96. get
  97. {
  98. IEnumerable<PropertyInfo> columnProperties = base.ColumnProperties;
  99.  
  100. return OrderPropertiesAsInDbTable(columnProperties);
  101. }
  102. }
  103.  
  104. public IQueryable<TObject> Query
  105. {
  106. get { return DbSet.AsQueryable(); }
  107. }
  108.  
  109. public virtual TObject[] All()
  110. {
  111. return Queryable.ToArray();
  112. }
  113.  
  114. public virtual IEnumerable<TObject> GetMany(Expression<Func<TObject, bool>> where)
  115. {
  116. return Queryable.Where(where).ToList();
  117. }
  118.  
  119. public IQueryable<IGrouping<TKey, TObject>> GroupBy<TKey>(Expression<Func<TObject, TKey>> groupBy)
  120. {
  121. try
  122. {
  123. return _queryFiltered.GroupBy(groupBy);
  124. }
  125. finally
  126. {
  127. _queryWithInclude = null;
  128. _queryOrdered = null;
  129. _queryFiltered = null;
  130. }
  131. }
  132.  
  133. public virtual IRepositoryFiltered<TObject> Where(Expression<Func<TObject, bool>> predicate)
  134. {
  135. _queryFiltered = Queryable.Where(predicate);
  136. return this;
  137. }
  138.  
  139. public TObject FirstOrDefault(Expression<Func<TObject, bool>> predicate)
  140. {
  141. return Queryable.FirstOrDefault(predicate);
  142. }
  143.  
  144. public TObject First(Expression<Func<TObject, bool>> predicate)
  145. {
  146. return Queryable.First(predicate);
  147. }
  148.  
  149. public TObject SingleOrDefault(Expression<Func<TObject, bool>> predicate)
  150. {
  151. return Queryable.SingleOrDefault(predicate);
  152. }
  153.  
  154. public TObject Single(Expression<Func<TObject, bool>> predicate)
  155. {
  156. TObject result = Queryable.SingleOrDefault(predicate);
  157. if (result == null)
  158. throw new MwDbException("No records found for query: " + predicate.Body);
  159.  
  160. return result;
  161. }
  162.  
  163. public IRepositoryInclude<TObject> Include(Expression<Func<TObject, object>> entityToInclude)
  164. {
  165. string[] expressionString = entityToInclude.Body.ToString().Split(new[] { '.' });
  166. string path = string.Join(".", expressionString.Skip(1));
  167. return Include(path);
  168. }
  169.  
  170.  
  171. public bool Contains(Expression<Func<TObject, bool>> predicate)
  172. {
  173. return Queryable.Any(predicate);
  174. }
  175.  
  176. public virtual TObject Create(TObject TObject)
  177. {
  178. TObject newEntry = DbSet.Add(TObject);
  179.  
  180. return newEntry;
  181. }
  182.  
  183. public virtual int Update(TObject TObject)
  184. {
  185. DbEntityEntry<TObject> entry = Context.Entry(TObject);
  186.  
  187. DbSet.Attach(TObject);
  188.  
  189. entry.State = EntityState.Modified;
  190.  
  191. return 0;
  192. }
  193.  
  194. public virtual int Delete(Expression<Func<TObject, bool>> predicate)
  195. {
  196. TObject[] objects = Where(predicate).Get();
  197. foreach (TObject obj in objects)
  198. DbSet.Remove(obj);
  199.  
  200. return 0;
  201. }
  202.  
  203. public void Delete(TObject TObject)
  204. {
  205. DbSet.Remove(TObject);
  206. }
  207.  
  208. public void BulkInsertOrUpdate(IEnumerable<TObject> list, Expression<Func<TObject, object>> mergeKey)
  209. {
  210. BulkInsertOrUpdate(list, mergeKey, new Expression<Func<TObject, object>>[0]);
  211. }
  212.  
  213. public void BulkInsertOrUpdate(IEnumerable<TObject> list, Expression<Func<TObject, object>> mergeKey, params Expression<Func<TObject, object>>[] skipUpdateFields)
  214. {
  215. var columns = GetColumnPropertyInfos();
  216. var importTable = BuildTemporaryImportTable(list, columns);
  217. var query = BuildMergeQuery(GetPropertyNameFromExpression(mergeKey), skipUpdateFields, importTable.TableName, columns);
  218. ExecuteSqlCommand(query.ToString());
  219. }
  220.  
  221. public void BulkInsert(IEnumerable<TObject> list)
  222. {
  223. var columns = GetColumnPropertyInfos();
  224. var importTable = BuildTemporaryImportTable(list, columns);
  225. var query = BuildInsertQuery(importTable.TableName, columns);
  226. ExecuteSqlCommand(query.ToString());
  227. }
  228.  
  229. private List<PropertyInfo> GetColumnPropertyInfos()
  230. {
  231. var columns = new List<PropertyInfo>();
  232. foreach (PropertyInfo p in ColumnProperties)
  233. {
  234. string stringType = p.PropertyType.ToString();
  235. if (!stringType.StartsWith("System.")) continue;
  236.  
  237. Type type = p.PropertyType;
  238. if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
  239. {
  240. stringType = Nullable.GetUnderlyingType(type).ToString();
  241. }
  242.  
  243. if (!stringType.Substring("System.".Length).IsIn(
  244. "SByte",
  245. "Byte",
  246. "Int16",
  247. "UInt16",
  248. "Int32",
  249. "UInt32",
  250. "Int64",
  251. "UInt64",
  252. "Char",
  253. "Single",
  254. "Double",
  255. "DateTime",
  256. "String",
  257. "Boolean",
  258. "Decimal"))
  259. continue;
  260.  
  261. columns.Add(p);
  262. }
  263.  
  264. //if (ColumnProperties.Count() != columns.Count)
  265. //{
  266. // var firstMissingColumn = ColumnProperties.Select(i => i.Name).Except(columns.Select(i => i.Name)).First();
  267. // throw new MwApplicationException("bulk import error: missing column " + firstMissingColumn);
  268. //}
  269.  
  270. return columns;
  271. }
  272.  
  273. private DataTable BuildTemporaryImportTable(IEnumerable<TObject> list, List<PropertyInfo> columns)
  274. {
  275. var dt = new DataTable
  276. {
  277. TableName = "#tmpImport"
  278. };
  279.  
  280. foreach (PropertyInfo p in columns)
  281. {
  282. Type type = p.PropertyType;
  283.  
  284. if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
  285. dt.Columns.Add(new DataColumn(p.Name, Nullable.GetUnderlyingType(type)));
  286. else
  287. dt.Columns.Add(new DataColumn(p.Name, type));
  288. }
  289.  
  290. foreach (TObject item in list)
  291. {
  292. DataRow row = dt.NewRow();
  293. foreach (PropertyInfo columnProperty in columns)
  294. {
  295. object value = columnProperty.GetValue(item, null);
  296. if (value != null)
  297. row[columnProperty.Name] = value;
  298. else
  299. row[columnProperty.Name] = DBNull.Value;
  300. }
  301. dt.Rows.Add(row);
  302. }
  303.  
  304. PopulateTemporaryImportTable(columns, dt);
  305.  
  306. return dt;
  307. }
  308.  
  309. private void PopulateTemporaryImportTable(IEnumerable<PropertyInfo> columns, DataTable importTable)
  310. {
  311. var fields = string.Join(",", columns.Select(i => "[" + i.Name + "]"));
  312. var sql = string.Format(
  313. "IF OBJECT_ID('tempdb..{0}', 'U') IS NOT NULL{2} DROP TABLE {0}; {2}{2} select top 0 {3} into {0} from {1}",
  314. importTable.TableName, TableName, Environment.NewLine, fields);
  315. ExecuteSqlCommand(sql);
  316.  
  317. using (var bulkCopy = new SqlBulkCopy(GetSqlConnection(), SqlBulkCopyOptions.Default, (SqlTransaction)_unitOfWork.Transaction.UnderlyingTransaction))
  318. {
  319. //Setting timeout to 0 means no time out for this command will not timeout until upload complete.
  320. //Change as per you
  321. bulkCopy.BulkCopyTimeout = 0;
  322. bulkCopy.DestinationTableName = importTable.TableName;
  323. //write the data in the "dataTable"
  324. bulkCopy.WriteToServer(importTable);
  325. }
  326. }
  327.  
  328. private StringBuilder BuildMergeQuery(string mergeKeyName, IEnumerable<Expression<Func<TObject, object>>> skipUpdateFields, string temporaryTableName, List<PropertyInfo> columns)
  329. {
  330. var newLine = Environment.NewLine;
  331.  
  332. var query = new StringBuilder();
  333. query.AppendFormat("MERGE {0} AS Target {1}", TableName, newLine);
  334. query.AppendFormat("USING {0} as Source {1}", temporaryTableName, newLine);
  335. query.AppendFormat("ON Target.[{0}] = Source.[{0}] {1}", mergeKeyName, newLine);
  336.  
  337. var updateFields = GetUpdateFields(skipUpdateFields, mergeKeyName, columns);
  338. var insertFields = GetInsertFields(columns);
  339.  
  340. if (updateFields.Any())
  341. {
  342. query.AppendFormat("WHEN MATCHED THEN UPDATE SET {0}", newLine);
  343. query.Append(string.Join("," + newLine, updateFields));
  344. }
  345.  
  346. query.AppendLine(" WHEN NOT MATCHED BY TARGET THEN");
  347. query.AppendFormat("INSERT ({0}) {1}", string.Join(",", insertFields.Select(i => "[" + i + "]")), newLine);
  348. query.AppendFormat("VALUES ({0});", string.Join(",", insertFields.Select(i => "Source." + "[" + i + "]")));
  349. return query;
  350. }
  351.  
  352. private StringBuilder BuildInsertQuery(string temporaryTableName, List<PropertyInfo> columns)
  353. {
  354. var query = new StringBuilder();
  355. var insertFields = GetInsertFields(columns);
  356. query.AppendFormat("INSERT INTO {0} ({1}) {2}", TableName, string.Join(",", insertFields.Select(i => "[" + i + "]")), Environment.NewLine);
  357. query.AppendFormat("SELECT {0}", string.Join(",", insertFields.Select(i => "[" + i + "]")));
  358. query.AppendFormat("FROM {0};", temporaryTableName);
  359. return query;
  360. }
  361.  
  362. public virtual int Count
  363. {
  364. get { return DbSet.Count(); }
  365. }
  366.  
  367. public virtual TObject[] Get()
  368. {
  369. try
  370. {
  371. return Queryable.ToArray();
  372. }
  373. finally
  374. {
  375. _queryWithInclude = null;
  376. _queryOrdered = null;
  377. _queryFiltered = null;
  378. }
  379. }
  380.  
  381. public virtual int Sum(Expression<Func<TObject, int?>> selector)
  382. {
  383. try
  384. {
  385. if (_queryOrdered != null)
  386. {
  387. return _queryOrdered.Sum(selector) ?? 0;
  388. }
  389.  
  390. return _queryFiltered.Sum(selector) ?? 0;
  391. }
  392. finally
  393. {
  394. _queryWithInclude = null;
  395. _queryOrdered = null;
  396. _queryFiltered = null;
  397. }
  398. }
  399.  
  400. public TObject FirstOrDefault()
  401. {
  402. try
  403. {
  404. return Queryable.FirstOrDefault();
  405. }
  406. finally
  407. {
  408. _queryWithInclude = null;
  409. _queryOrdered = null;
  410. _queryFiltered = null;
  411. }
  412. }
  413.  
  414. public virtual IRepositoryOrdered<TObject> OrderByDescending<TKey>(Expression<Func<TObject, TKey>> orderBy) where TKey : IComparable
  415. {
  416. _queryOrdered = Queryable.OrderByDescending(orderBy);
  417. return this;
  418. }
  419.  
  420. public virtual IRepositoryOrdered<TObject> OrderBy<TKey>(Expression<Func<TObject, TKey>> orderBy) where TKey : IComparable
  421. {
  422. _queryOrdered = Queryable.OrderBy(orderBy);
  423. return this;
  424. }
  425.  
  426. public virtual TObject Find(Expression<Func<TObject, bool>> predicate)
  427. {
  428. return Queryable.FirstOrDefault(predicate);
  429. }
  430.  
  431. public IRepositoryOrdered<TObject> ThenByDescending<TKey>(Expression<Func<TObject, TKey>> orderBy) where TKey : IComparable
  432. {
  433. _queryOrdered = Queryable.OrderBy(orderBy);
  434. return this;
  435. }
  436.  
  437. public IRepositoryOrdered<TObject> ThenBy<TKey>(Expression<Func<TObject, TKey>> orderBy) where TKey : IComparable
  438. {
  439. _queryOrdered = Queryable.OrderBy(orderBy);
  440. return this;
  441. }
  442.  
  443. /// <summary>
  444. /// </summary>
  445. /// <param name="index">Specified the page index.</param>
  446. /// <param name="size">Specified the page size</param>
  447. /// <returns></returns>
  448. public TObject[] Page(int index = 0, int size = 50)
  449. {
  450. int totalCount;
  451. return Page(out totalCount, false, index, size);
  452. }
  453.  
  454. /// <summary>
  455. /// </summary>
  456. /// <param name="totalCount">Total count of before apply paging</param>
  457. /// <param name="index">Specified the page index.</param>
  458. /// <param name="size">Specified the page size</param>
  459. /// <returns></returns>
  460. public TObject[] Page(out int totalCount, int index = 0, int size = 50)
  461. {
  462. return Page(out totalCount, true, index, size);
  463. }
  464.  
  465. protected void ConfigureConnection()
  466. {
  467. if (Context.Database.Connection.State == ConnectionState.Closed)
  468. Context.Database.Connection.Open();
  469.  
  470. DbCommand command = Context.Database.Connection.CreateCommand();
  471. command.CommandText = "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;";
  472.  
  473. try
  474. {
  475. command.ExecuteNonQuery();
  476. }
  477. catch (SqlException)
  478. {
  479. Context.Database.Connection.Open();
  480. command.ExecuteNonQuery();
  481. }
  482. }
  483.  
  484. public virtual IQueryable<TObject> GetAllLazyLoad(Expression<Func<TObject, bool>> filter, params Expression<Func<TObject, object>>[] children)
  485. {
  486. children.ToList().ForEach(x => DbSet.Include(x).Load());
  487. return DbSet.AsQueryable();
  488. }
  489.  
  490. private TObject[] Page(out int totalCount, bool countTotal, int index = 0, int size = 50)
  491. {
  492. int skipCount = index * size;
  493. try
  494. {
  495. TObject[] result = skipCount == 0
  496. ? Queryable.Take(size).ToArray()
  497. : Queryable.Skip(skipCount).Take(size).ToArray();
  498.  
  499. if (countTotal)
  500. totalCount = Queryable.Count();
  501. else
  502. totalCount = -1;
  503.  
  504. return result;
  505. }
  506. finally
  507. {
  508. _queryWithInclude = null;
  509. _queryOrdered = null;
  510. _queryFiltered = null;
  511. }
  512. }
  513.  
  514. protected IRepositoryInclude<TObject> Include(string path)
  515. {
  516. _queryWithInclude = _queryWithInclude != null ? _queryWithInclude.Include(path) : DbSet.Include(path);
  517. return this;
  518. }
  519.  
  520. private List<string> GetUpdateFields(IEnumerable<Expression<Func<TObject, object>>> skipUpdateFields, string matchKey, IEnumerable<PropertyInfo> columns)
  521. {
  522. var skipFields = new List<string>
  523. {
  524. matchKey.ToLower()
  525. };
  526. foreach (var skipUpdateField in skipUpdateFields)
  527. {
  528. skipFields.Add(GetPropertyNameFromExpression(skipUpdateField).ToLower());
  529. }
  530.  
  531. var updateFields = new List<string>();
  532. foreach (PropertyInfo columnProperty in columns)
  533. {
  534. if (skipFields.Contains(columnProperty.Name.ToLower()))
  535. continue;
  536.  
  537. updateFields.Add(string.Format("Target.[{0}] = Source.[{0}]", columnProperty.Name));
  538. }
  539. return updateFields;
  540. }
  541.  
  542. protected void ExecuteSqlCommand(string query)
  543. {
  544. SqlCommand command = CreateSqlCommand(query);
  545.  
  546. command.CommandTimeout = (60 * 5);
  547. command.ExecuteNonQuery();
  548. }
  549.  
  550. protected SqlCommand CreateSqlCommand(string query)
  551. {
  552. SqlConnection dbConnection = GetSqlConnection();
  553. return new SqlCommand(query, dbConnection, (SqlTransaction)_unitOfWork.Transaction.UnderlyingTransaction);
  554. }
  555.  
  556. private SqlConnection GetSqlConnection()
  557. {
  558. var dbConnection = Context.Database.Connection as SqlConnection;
  559.  
  560. if (dbConnection.State == ConnectionState.Closed)
  561. dbConnection.Open();
  562. return dbConnection;
  563. }
  564.  
  565. private IEnumerable<PropertyInfo> OrderPropertiesAsInDbTable(IEnumerable<PropertyInfo> propertyInfos)
  566. {
  567. const string query = "select COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS " +
  568. "where TABLE_SCHEMA = 'dbo' " +
  569. "and '[dbo].['+rtrim(TABLE_NAME)+']' = {0} " +
  570. "order by ORDINAL_POSITION";
  571.  
  572. DbRawSqlQuery<string> columns = Context.Database.SqlQuery<string>(query, TableName);
  573.  
  574. var result = new List<PropertyInfo>();
  575. foreach (string column in columns)
  576. {
  577. PropertyInfo property = propertyInfos.FirstOrDefault(pi => pi.Name.ToLower().Trim() == column.ToLower().Trim());
  578. if (property == null)
  579. throw new Exception("Cannot find field:" + column);
  580.  
  581. result.Add(property);
  582. }
  583.  
  584. return result;
  585. }
  586.  
  587. protected List<string> GetInsertFields(List<PropertyInfo> columns)
  588. {
  589. string query =
  590. "select COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA = 'dbo' and COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1 and '[dbo].['+rtrim(TABLE_NAME)+']' = {0} order by ORDINAL_POSITION";
  591.  
  592. string identity = Context.Database.SqlQuery<string>(query, TableName).FirstOrDefault();
  593.  
  594. return columns.Where(i => i.Name != identity).Select(i => i.Name).ToList();
  595. }
  596. }
  597. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement