(转)EntityFramework.Extensions
using System;using System.Collections.Generic;using System.Data;using System.Data.Common;using System.Data.Common.CommandTrees;using System.Data.Entity;using System.Data.EntityClient;using System.Data.Metadata.Edm;using System.Data.Objects.DataClasses;using System.Data.SqlClient;using System.Linq;using System.Linq.Dynamic;using System.Linq.Expressions;using System.Reflection;using System.Text;using System.Data.Objects;using EntityFramework.Mapping;using EntityFramework.Reflection;namespace EntityFramework.Extensions{ /// <summary> /// An extensions class for batch queries. /// </summary> public static class BatchExtensions { /// <summary> /// Executes a delete statement using the query to filter the rows to be deleted. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="source">The source used to determine the table to delete from.</param> /// <param name="query">The IQueryable used to generate the where clause for the delete statement.</param> /// <returns>The number of row deleted.</returns> /// <remarks> /// When executing this method, the statement is immediately executed on the database provider /// and is not part of the change tracking system. Also, changes will not be reflected on /// any entities that have already been materialized in the current context. /// </remarks> public static int Delete<TEntity>( this ObjectSet<TEntity> source, IQueryable<TEntity> query) where TEntity : class { if (source == null) throw new ArgumentNullException("source"); if (query == null) throw new ArgumentNullException("query"); ObjectContext objectContext = source.Context; if (objectContext == null) throw new ArgumentException("The ObjectContext for the source query can not be null.", "source"); EntityMap entityMap = source.GetEntityMap<TEntity>(); if (entityMap == null) throw new ArgumentException("Could not load the entity mapping information for the source ObjectSet.", "source"); ObjectQuery<TEntity> objectQuery = query.ToObjectQuery(); if (objectQuery == null) throw new ArgumentException("The query must be of type ObjectQuery or DbQuery.", "query"); return Delete(objectContext, entityMap, objectQuery); } /// <summary> /// Executes a delete statement using an expression to filter the rows to be deleted. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="source">The source used to determine the table to delete from.</param> /// <param name="filterExpression">The filter expression used to generate the where clause for the delete statement.</param> /// <returns>The number of row deleted.</returns> /// <example>Delete all users with email domain @test.com. /// <code><![CDATA[ /// var db = new TrackerEntities(); /// string emailDomain = "@test.com"; /// int count = db.Users.Delete(u => u.Email.EndsWith(emailDomain)); /// ]]></code> /// </example> /// <remarks> /// When executing this method, the statement is immediately executed on the database provider /// and is not part of the change tracking system. Also, changes will not be reflected on /// any entities that have already been materialized in the current context. /// </remarks> public static int Delete<TEntity>( this ObjectSet<TEntity> source, Expression<Func<TEntity, bool>> filterExpression) where TEntity : class { if (source == null) throw new ArgumentNullException("source"); if (filterExpression == null) throw new ArgumentNullException("filterExpression"); return source.Delete(source.Where(filterExpression)); } /// <summary> /// Executes a delete statement using the query to filter the rows to be deleted. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="source">The source used to determine the table to delete from.</param> /// <param name="query">The IQueryable used to generate the where clause for the delete statement.</param> /// <returns>The number of row deleted.</returns> /// <remarks> /// When executing this method, the statement is immediately executed on the database provider /// and is not part of the change tracking system. Also, changes will not be reflected on /// any entities that have already been materialized in the current context. /// </remarks> public static int Delete<TEntity>( this DbSet<TEntity> source, IQueryable<TEntity> query) where TEntity : class { if (source == null) throw new ArgumentNullException("source"); if (query == null) throw new ArgumentNullException("query"); ObjectQuery<TEntity> sourceQuery = source.ToObjectQuery(); if (sourceQuery == null) throw new ArgumentException("The query must be of type ObjectQuery or DbQuery.", "source"); ObjectContext objectContext = sourceQuery.Context; if (objectContext == null) throw new ArgumentException("The ObjectContext for the source query can not be null.", "source"); EntityMap entityMap = sourceQuery.GetEntityMap<TEntity>(); if (entityMap == null) throw new ArgumentException("Could not load the entity mapping information for the source ObjectSet.", "source"); ObjectQuery<TEntity> objectQuery = query.ToObjectQuery(); if (objectQuery == null) throw new ArgumentException("The query must be of type ObjectQuery or DbQuery.", "query"); return Delete(objectContext, entityMap, objectQuery); } /// <summary> /// Executes a delete statement using an expression to filter the rows to be deleted. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="source">The source used to determine the table to delete from.</param> /// <param name="filterExpression">The filter expression used to generate the where clause for the delete statement.</param> /// <returns>The number of row deleted.</returns> /// <example>Delete all users with email domain @test.com. /// <code><![CDATA[ /// var db = new TrackerContext(); /// string emailDomain = "@test.com"; /// int count = db.Users.Delete(u => u.Email.EndsWith(emailDomain)); /// ]]></code> /// </example> /// <remarks> /// When executing this method, the statement is immediately executed on the database provider /// and is not part of the change tracking system. Also, changes will not be reflected on /// any entities that have already been materialized in the current context. /// </remarks> public static int Delete<TEntity>( this DbSet<TEntity> source, Expression<Func<TEntity, bool>> filterExpression) where TEntity : class { if (source == null) throw new ArgumentNullException("source"); if (filterExpression == null) throw new ArgumentNullException("filterExpression"); return source.Delete(source.Where(filterExpression)); } /// <summary> /// Executes an update statement using the query to filter the rows to be updated. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="source">The source used to determine the table to update.</param> /// <param name="query">The query used to generate the where clause.</param> /// <param name="updateExpression">The MemberInitExpression used to indicate what is updated.</param> /// <returns>The number of row updated.</returns> /// <remarks> /// When executing this method, the statement is immediately executed on the database provider /// and is not part of the change tracking system. Also, changes will not be reflected on /// any entities that have already been materialized in the current context. /// </remarks> public static int Update<TEntity>( this ObjectSet<TEntity> source, IQueryable<TEntity> query, Expression<Func<TEntity, TEntity>> updateExpression) where TEntity : class { if (source == null) throw new ArgumentNullException("source"); if (query == null) throw new ArgumentNullException("query"); if (updateExpression == null) throw new ArgumentNullException("updateExpression"); ObjectContext objectContext = source.Context; if (objectContext == null) throw new ArgumentException("The ObjectContext for the source query can not be null.", "source"); EntityMap entityMap = source.GetEntityMap<TEntity>(); if (entityMap == null) throw new ArgumentException("Could not load the entity mapping information for the source ObjectSet.", "source"); ObjectQuery<TEntity> objectQuery = query.ToObjectQuery(); if (objectQuery == null) throw new ArgumentException("The query must be of type ObjectQuery or DbQuery.", "query"); return Update(objectContext, entityMap, objectQuery, updateExpression); } /// <summary> /// Executes an update statement using an expression to filter the rows that are updated. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="source">The source used to determine the table to update.</param> /// <param name="filterExpression">The filter expression used to generate the where clause.</param> /// <param name="updateExpression">The MemberInitExpression used to indicate what is updated.</param> /// <returns>The number of row updated.</returns> /// <example>Update all users in the test.com domain to be inactive. /// <code><![CDATA[ /// var db = new TrackerEntities(); /// string emailDomain = "@test.com"; /// int count = db.Users.Update( /// u => u.Email.EndsWith(emailDomain), /// u => new User { IsApproved = false, LastActivityDate = DateTime.Now }); /// ]]></code> /// </example> /// <remarks> /// When executing this method, the statement is immediately executed on the database provider /// and is not part of the change tracking system. Also, changes will not be reflected on /// any entities that have already been materialized in the current context. /// </remarks> public static int Update<TEntity>( this ObjectSet<TEntity> source, Expression<Func<TEntity, bool>> filterExpression, Expression<Func<TEntity, TEntity>> updateExpression) where TEntity : class { if (source == null) throw new ArgumentNullException("source"); if (filterExpression == null) throw new ArgumentNullException("filterExpression"); return source.Update(source.Where(filterExpression), updateExpression); } /// <summary> /// Executes an update statement using the query to filter the rows to be updated. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="source">The source used to determine the table to update.</param> /// <param name="query">The query used to generate the where clause.</param> /// <param name="updateExpression">The MemberInitExpression used to indicate what is updated.</param> /// <returns>The number of row updated.</returns> /// <remarks> /// When executing this method, the statement is immediately executed on the database provider /// and is not part of the change tracking system. Also, changes will not be reflected on /// any entities that have already been materialized in the current context. /// </remarks> public static int Update<TEntity>( this DbSet<TEntity> source, IQueryable<TEntity> query, Expression<Func<TEntity, TEntity>> updateExpression) where TEntity : class { if (source == null) throw new ArgumentNullException("source"); if (query == null) throw new ArgumentNullException("query"); if (updateExpression == null) throw new ArgumentNullException("updateExpression"); ObjectQuery<TEntity> sourceQuery = source.ToObjectQuery(); if (sourceQuery == null) throw new ArgumentException("The query must be of type ObjectQuery or DbQuery.", "source"); ObjectContext objectContext = sourceQuery.Context; if (objectContext == null) throw new ArgumentException("The ObjectContext for the source query can not be null.", "source"); EntityMap entityMap = sourceQuery.GetEntityMap<TEntity>(); if (entityMap == null) throw new ArgumentException("Could not load the entity mapping information for the source.", "source"); ObjectQuery<TEntity> objectQuery = query.ToObjectQuery(); if (objectQuery == null) throw new ArgumentException("The query must be of type ObjectQuery or DbQuery.", "query"); return Update(objectContext, entityMap, objectQuery, updateExpression); } /// <summary> /// Executes an update statement using an expression to filter the rows that are updated. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="source">The source used to determine the table to update.</param> /// <param name="filterExpression">The filter expression used to generate the where clause.</param> /// <param name="updateExpression">The MemberInitExpression used to indicate what is updated.</param> /// <returns>The number of row updated.</returns> /// <example>Update all users in the test.com domain to be inactive. /// <code><![CDATA[ /// var db = new TrackerContext(); /// string emailDomain = "@test.com"; /// int count = db.Users.Update( /// u => u.Email.EndsWith(emailDomain), /// u => new User { IsApproved = false, LastActivityDate = DateTime.Now }); /// ]]></code> /// </example> /// <remarks> /// When executing this method, the statement is immediately executed on the database provider /// and is not part of the change tracking system. Also, changes will not be reflected on /// any entities that have already been materialized in the current context. /// </remarks> public static int Update<TEntity>( this DbSet<TEntity> source, Expression<Func<TEntity, bool>> filterExpression, Expression<Func<TEntity, TEntity>> updateExpression) where TEntity : class { if (source == null) throw new ArgumentNullException("source"); if (filterExpression == null) throw new ArgumentNullException("filterExpression"); return source.Update(source.Where(filterExpression), updateExpression); } private static int Delete<TEntity>(ObjectContext objectContext, EntityMap entityMap, ObjectQuery<TEntity> query) where TEntity : class { DbConnection deleteConnection = null; DbTransaction deleteTransaction = null; DbCommand deleteCommand = null; bool ownConnection = false; bool ownTransaction = false; try { // get store connection and transaction var store = GetStore(objectContext); deleteConnection = store.Item1; deleteTransaction = store.Item2; if (deleteConnection.State != ConnectionState.Open) { deleteConnection.Open(); ownConnection = true; } if (deleteTransaction == null) { deleteTransaction = deleteConnection.BeginTransaction(); ownTransaction = true; } deleteCommand = deleteConnection.CreateCommand(); deleteCommand.Transaction = deleteTransaction; if (objectContext.CommandTimeout.HasValue) deleteCommand.CommandTimeout = objectContext.CommandTimeout.Value; var innerSelect = GetSelectSql(query, entityMap, deleteCommand); var sqlBuilder = new StringBuilder(innerSelect.Length * 2); sqlBuilder.Append("DELETE "); sqlBuilder.Append(entityMap.TableName); sqlBuilder.AppendLine(); sqlBuilder.AppendFormat("FROM {0} AS j0 INNER JOIN (", entityMap.TableName); sqlBuilder.AppendLine(); sqlBuilder.AppendLine(innerSelect); sqlBuilder.Append(") AS j1 ON ("); bool wroteKey = false; foreach (var keyMap in entityMap.KeyMaps) { if (wroteKey) sqlBuilder.Append(" AND "); sqlBuilder.AppendFormat("j0.{0} = j1.{0}", keyMap.ColumnName); wroteKey = true; } sqlBuilder.Append(")"); deleteCommand.CommandText = sqlBuilder.ToString(); int result = deleteCommand.ExecuteNonQuery(); // only commit if created transaction if (ownTransaction) deleteTransaction.Commit(); return result; } finally { if (deleteCommand != null) deleteCommand.Dispose(); if (deleteTransaction != null && ownTransaction) deleteTransaction.Dispose(); if (deleteConnection != null && ownConnection) deleteConnection.Close(); } } private static int Update<TEntity>(ObjectContext objectContext, EntityMap entityMap, ObjectQuery<TEntity> query, Expression<Func<TEntity, TEntity>> updateExpression) where TEntity : class { DbConnection updateConnection = null; DbTransaction updateTransaction = null; DbCommand updateCommand = null; bool ownConnection = false; bool ownTransaction = false; try { // get store connection and transaction var store = GetStore(objectContext); updateConnection = store.Item1; updateTransaction = store.Item2; if (updateConnection.State != ConnectionState.Open) { updateConnection.Open(); ownConnection = true; } // use existing transaction or create new if (updateTransaction == null) { updateTransaction = updateConnection.BeginTransaction(); ownTransaction = true; } updateCommand = updateConnection.CreateCommand(); updateCommand.Transaction = updateTransaction; if (objectContext.CommandTimeout.HasValue) updateCommand.CommandTimeout = objectContext.CommandTimeout.Value; var innerSelect = GetSelectSql(query, entityMap, updateCommand); var sqlBuilder = new StringBuilder(innerSelect.Length * 2); sqlBuilder.Append("UPDATE "); sqlBuilder.Append(entityMap.TableName); sqlBuilder.AppendLine(" SET "); var memberInitExpression = updateExpression.Body as MemberInitExpression; if (memberInitExpression == null) throw new ArgumentException("The update expression must be of type MemberInitExpression.", "updateExpression"); int nameCount = 0; bool wroteSet = false; foreach (MemberBinding binding in memberInitExpression.Bindings) { if (wroteSet) sqlBuilder.AppendLine(", "); string propertyName = binding.Member.Name; string columnName = entityMap.PropertyMaps .Where(p => p.PropertyName == propertyName) .Select(p => p.ColumnName) .FirstOrDefault(); string parameterName = "p__update__" + nameCount++; var memberAssignment = binding as MemberAssignment; if (memberAssignment == null) throw new ArgumentException("The update expression MemberBinding must only by type MemberAssignment.", "updateExpression"); object value; if (memberAssignment.Expression.NodeType == ExpressionType.Constant) { var constantExpression = memberAssignment.Expression as ConstantExpression; if (constantExpression == null) throw new ArgumentException("The MemberAssignment expression is not a ConstantExpression.", "updateExpression"); value = constantExpression.Value; } else { LambdaExpression lambda = Expression.Lambda(memberAssignment.Expression, null); value = lambda.Compile().DynamicInvoke(); } var parameter = updateCommand.CreateParameter(); parameter.ParameterName = parameterName; parameter.Value = value; updateCommand.Parameters.Add(parameter); sqlBuilder.AppendFormat("{0} = @{1}", columnName, parameterName); wroteSet = true; } sqlBuilder.AppendLine(" "); sqlBuilder.AppendFormat("FROM {0} AS j0 INNER JOIN (", entityMap.TableName); sqlBuilder.AppendLine(); sqlBuilder.AppendLine(innerSelect); sqlBuilder.Append(") AS j1 ON ("); bool wroteKey = false; foreach (var keyMap in entityMap.KeyMaps) { if (wroteKey) sqlBuilder.Append(" AND "); sqlBuilder.AppendFormat("j0.{0} = j1.{0}", keyMap.ColumnName); wroteKey = true; } sqlBuilder.Append(")"); updateCommand.CommandText = sqlBuilder.ToString(); int result = updateCommand.ExecuteNonQuery(); // only commit if created transaction if (ownTransaction) updateTransaction.Commit(); return result; } finally { if (updateCommand != null) updateCommand.Dispose(); if (updateTransaction != null && ownTransaction) updateTransaction.Dispose(); if (updateConnection != null && ownConnection) updateConnection.Close(); } } private static Tuple<DbConnection, DbTransaction> GetStore(ObjectContext objectContext) { DbConnection dbConnection = objectContext.Connection; var entityConnection = dbConnection as EntityConnection; // by-pass entity connection if (entityConnection == null) return new Tuple<DbConnection, DbTransaction>(dbConnection, null); DbConnection connection = entityConnection.StoreConnection; // get internal transaction dynamic connectionProxy = new DynamicProxy(entityConnection); dynamic entityTransaction = connectionProxy.CurrentTransaction; if (entityTransaction == null) return new Tuple<DbConnection, DbTransaction>(connection, null); DbTransaction transaction = entityTransaction.StoreTransaction; return new Tuple<DbConnection, DbTransaction>(connection, transaction); } private static string GetSelectSql<TEntity>(ObjectQuery<TEntity> query, EntityMap entityMap, DbCommand command) where TEntity : class { // changing query to only select keys var selector = new StringBuilder(50); selector.Append("new("); foreach (var propertyMap in entityMap.KeyMaps) { if (selector.Length > 4) selector.Append((", ")); selector.Append(propertyMap.PropertyName); } selector.Append(")"); var selectQuery = DynamicQueryable.Select(query, selector.ToString()); var objectQuery = selectQuery as ObjectQuery; if (objectQuery == null) throw new ArgumentException("The query must be of type ObjectQuery.", "query"); string innerJoinSql = objectQuery.ToTraceString(); // create parameters foreach (var objectParameter in objectQuery.Parameters) { var parameter = command.CreateParameter(); parameter.ParameterName = objectParameter.Name; parameter.Value = objectParameter.Value; command.Parameters.Add(parameter); } return innerJoinSql; } }}(转)EntityFramework.Extensions的更多相关文章
- 测试EntityFramework,Z.EntityFramework.Extensions,原生语句在不同的查询中的表现。原来池化与非池化设定是有巨大的影响的。
Insert测试,只测试1000条的情况,多了在实际的项目中应该就要另行处理了. using System; using System.Collections.Generic; using Syste ...
- 第九节: EF的性能篇(二) 之 Z.EntityFramework.Extensions程序集解决EF的性能问题
一. 综述 该模块主要介绍:EF的性能优化插件Z.EntityFramework.Extensions,该插件收费. (一). 简介 1. 相关网站:http://www.zzzprojects.co ...
- 【EF】解决EF批量操作,Z.EntityFramework.Extensions 过期方案
方案一: 使用EntityFramework.Extended优点: 启下载量是Z.EntityFramework.Extensions的10倍+ 不会过期缺点:不能批量Insert 方案二:解决批量 ...
- 破解EFCore扩展Dll --- Z.EntityFramework.Extensions.EFCore
安装 Z.EntityFramework.Extensions.EFCore Install-Package Z.EntityFramework.Extensions.EFCore -Version ...
- 自己动手破解Z.EntityFramework.Extensions 4.0.11.0的方法
因为项目中使用到Z.EntityFramework.Extensions 和 Z.EntityFramework.Plus(免费开源)两个类库,但是Z.EntityFramework.Extensio ...
- EF 批量增删改 EntityFramework.Extensions
EntityFramework.Extensions 1.官方网站 http://entityframework-extensions.net/ 2 破解版 Z.EntityFramework.E ...
- EF批量插入数据(Z.EntityFramework.Extensions)
EF用原生的插入数据方法DbSet.ADD()和 DbSet.AddRange()都很慢.所以要做大型的批量插入只能另选它法. 1.Nugget 2.代码 using EF6._0Test.EF; u ...
- 采用EntityFramework.Extended 对EF进行扩展(Entity Framework 延伸系列2)
前言 Entity Framework 延伸系列目录 今天我们来讲讲EntityFramework.Extended 首先科普一下这个EntityFramework.Extended是什么,如下: 这 ...
- EntityFramework 优化建议
Entity Framework目前最新版本是6.1.3,当然Entity Framework 7 目前还是预览版,并不能投入正式生产环境,估计正式版16年第一季度会出来,了解过EF7的部分新特性后, ...
随机推荐
- 安装nginx流程
1.下载nginx压缩包: 下载nginx:http://nginx.org/en/download.html 本教程下载 nginx-1.14.0.zip(http://nginx.org/down ...
- u-boot之怎么实现分区
启动参数bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0中kernel在哪定义,为什么可以直接引用?针对这个问题展开思考最终定位到 ...
- LINUX查看网卡UUID
有时我们不小心将/etc/sysconfig/network-scripts/ifcfg-eth0(可以通过此文件进行查看UUID)删除或者损坏,要重新编辑ifcfg-eth0文件时不知道网卡的UUI ...
- NOIP需要掌握的内容(大致
1.排序算法(快排.选择.冒泡.堆排序.二叉排序树.桶排序)2.DFS/BFS 剪枝 哈希表3.树 ①遍历 ②二叉树 ③二叉排序树(查找.生成.删除) ④堆(二叉堆.左偏树.堆排序) ...
- vim 中将 TAB 换成 4 个空格
最近开始学习Python,其语法简单,但是对代码格式要求比较严格.代码采用缩进方式,按照约定采用4个空格的缩进. Linux下配置vim编辑器中Tab键为4个空格方法: 1. 编辑文件: vi /et ...
- lodash 中常用的方法
odash是js集Array/Object/String/Function的Util于一身. lodash打包了Array/Object/String/Function里一些Api,好处是连ES6的也 ...
- SSRF-php初探
0x00 前言 1) SSRF的概念很好理解,请自行百度. 2) JAVA/PHP/PYTHON都存在SSRF漏洞(至于其他语言的情况,了解粗浅尚不得知). 3) SSRF的利用方式 ...
- cpp 区块链模拟示例(七) 补充 Merkle树
Merkle 树 完整的比特币数据库(也就是区块链)需要超过 140 Gb 的磁盘空间.因为比特币的去中心化特性,网络中的每个节点必须是独立,自给自足的,也就是每个节点必须存储一个区块链的完整副本.随 ...
- mysql索引相关
索引有主键索引.唯一索引.普通索引 单列索引,复合索引. 复合索引(a,b,c),可以理解是有三个索引,分别是a.b.c三个索引 前缀不是a的话,复合索引都不起作用,前缀用函数或者是范围,比如< ...
- Mockito学习(zz)
junitmaven软件测试框架项目管理 Mockito是一个流行的Mocking框架.它使用起来简单,学习成本很低,而且具有非常简洁的API,测试代码的可读性很高.因此它十分受欢迎,用 户群越来越 ...