From 3e8fed416d8c06455ac8f357b4f1fc4043821987 Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Thu, 20 Jun 2019 17:56:07 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E5=A2=9E=E5=8A=A0=20LambdaExpression=20?= =?UTF-8?q?=E6=89=A9=E5=B1=95=E6=96=B9=E6=B3=95=20And/Or/Not=20=E5=BF=AB?= =?UTF-8?q?=E9=80=9F=E6=8B=BC=E6=8E=A5=E8=A1=A8=E8=BE=BE=E5=BC=8F=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FreeSql.Extensions.LazyLoading.csproj | 2 +- .../LambadaExpressionExtensionsTest.cs | 43 ++++++++ .../Extensions/LambadaExpressionExtensions.cs | 98 +++++++++++++++++++ FreeSql/FreeSql.csproj | 2 +- FreeSql/FreeSql.xml | 41 ++++++++ .../FreeSql.Provider.MySql.csproj | 2 +- .../FreeSql.Provider.MySqlConnector.csproj | 2 +- .../FreeSql.Provider.Oracle.csproj | 2 +- .../FreeSql.Provider.PostgreSQL.csproj | 2 +- .../FreeSql.Provider.SqlServer.csproj | 2 +- .../FreeSql.Provider.Sqlite.csproj | 2 +- 11 files changed, 190 insertions(+), 8 deletions(-) create mode 100644 FreeSql.Tests/Extensions/LambadaExpressionExtensionsTest.cs create mode 100644 FreeSql/Extensions/LambadaExpressionExtensions.cs diff --git a/Extensions/FreeSql.Extensions.LazyLoading/FreeSql.Extensions.LazyLoading.csproj b/Extensions/FreeSql.Extensions.LazyLoading/FreeSql.Extensions.LazyLoading.csproj index 60966e88..5c32ade8 100644 --- a/Extensions/FreeSql.Extensions.LazyLoading/FreeSql.Extensions.LazyLoading.csproj +++ b/Extensions/FreeSql.Extensions.LazyLoading/FreeSql.Extensions.LazyLoading.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.6.11 + 0.6.12 true YeXiangQin FreeSql 扩展包,可实现【延时加载】属性. diff --git a/FreeSql.Tests/Extensions/LambadaExpressionExtensionsTest.cs b/FreeSql.Tests/Extensions/LambadaExpressionExtensionsTest.cs new file mode 100644 index 00000000..ca387c1e --- /dev/null +++ b/FreeSql.Tests/Extensions/LambadaExpressionExtensionsTest.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using Xunit; + +namespace FreeSql.Tests.Extensions { + public class LambadaExpressionExtensionsTest { + + [Fact] + public void And() { + Expression> where = a => a.id == Guid.Empty; + + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (a.\"id\" = '00000000-0000-0000-0000-000000000000' AND a.\"num\" > 0)", g.sqlite.Select().Where(where.And(b => b.num > 0)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (a.\"id\" = '00000000-0000-0000-0000-000000000000')", g.sqlite.Select().Where(where.And(false, b => b.num > 0)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (a.\"id\" = '00000000-0000-0000-0000-000000000000' AND a.\"num\" = 1 AND a.\"num\" = 2)", g.sqlite.Select().Where(where.And(b => b.num == 1).And(b => b.num == 2)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (a.\"id\" = '00000000-0000-0000-0000-000000000000')", g.sqlite.Select().Where(where.And(false, b => b.num == 1).And(false, c => c.num == 2)).ToSql().Replace("\r\n", "")); + } + + [Fact] + public void Or() { + Expression> where = a => a.id == Guid.Empty; + + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE ((a.\"id\" = '00000000-0000-0000-0000-000000000000' OR a.\"num\" > 0))", g.sqlite.Select().Where(where.Or(b => b.num > 0)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (a.\"id\" = '00000000-0000-0000-0000-000000000000')", g.sqlite.Select().Where(where.Or(false, b => b.num > 0)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (((a.\"id\" = '00000000-0000-0000-0000-000000000000' OR a.\"num\" = 1) OR a.\"num\" = 2))", g.sqlite.Select().Where(where.Or(b => b.num == 1).Or(b => b.num == 2)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (a.\"id\" = '00000000-0000-0000-0000-000000000000')", g.sqlite.Select().Where(where.Or(false, b => b.num == 1).Or(false, c => c.num == 2)).ToSql().Replace("\r\n", "")); + } + + [Fact] + public void Not() { + Expression> where = a => a.id == Guid.Empty; + + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (not(a.\"id\" = '00000000-0000-0000-0000-000000000000'))", g.sqlite.Select().Where(where.Not()).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (a.\"id\" = '00000000-0000-0000-0000-000000000000')", g.sqlite.Select().Where(where.Not(false)).ToSql().Replace("\r\n", "")); + } + + class testExpAddOr { + public Guid id { get; set; } + + public int num { get; set; } + } + } +} diff --git a/FreeSql/Extensions/LambadaExpressionExtensions.cs b/FreeSql/Extensions/LambadaExpressionExtensions.cs new file mode 100644 index 00000000..8a00b022 --- /dev/null +++ b/FreeSql/Extensions/LambadaExpressionExtensions.cs @@ -0,0 +1,98 @@ +using FreeSql; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace System.Linq.Expressions { + public static partial class LambadaExpressionExtensions { + + /// + /// 使用 and 拼接两个 lambda 表达式 + /// + /// + public static Expression> And(this Expression> exp1, Expression> exp2) => And(exp1, true, exp2); + /// + /// 使用 and 拼接两个 lambda 表达式 + /// + /// + /// + /// true 时生效 + /// + /// + public static Expression> And(this Expression> exp1, bool condition, Expression> exp2) { + if (condition == false) return exp1; + if (exp1 == null) return exp2; + if (exp2 == null) return exp1; + + ParameterExpression newParameter = Expression.Parameter(typeof(T), "c"); + NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter); + + var left = visitor.Replace(exp1.Body); + var right = visitor.Replace(exp2.Body); + var body = Expression.AndAlso(left, right); + return Expression.Lambda>(body, newParameter); + } + + /// + /// 使用 or 拼接两个 lambda 表达式 + /// + /// + public static Expression> Or(this Expression> exp1, Expression> exp2) => Or(exp1, true, exp2); + /// + /// 使用 or 拼接两个 lambda 表达式 + /// + /// + /// + /// true 时生效 + /// + /// + public static Expression> Or(this Expression> exp1, bool condition, Expression> exp2) { + if (condition == false) return exp1; + if (exp1 == null) return exp2; + if (exp2 == null) return exp1; + + ParameterExpression newParameter = Expression.Parameter(typeof(T), "c"); + NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter); + + var left = visitor.Replace(exp1.Body); + var right = visitor.Replace(exp2.Body); + var body = Expression.OrElse(left, right); + return Expression.Lambda>(body, newParameter); + } + + /// + /// 将 lambda 表达式取反 + /// + /// + /// + /// true 时生效 + /// + public static Expression> Not(this Expression> exp, bool condition = true) { + if (condition == false) return exp; + if (exp == null) return null; + + var candidateExpr = exp.Parameters[0]; + var body = Expression.Not(exp.Body); + return Expression.Lambda>(body, candidateExpr); + } + } + + internal class NewExpressionVisitor : ExpressionVisitor { + public ParameterExpression _newParameter { get; private set; } + public NewExpressionVisitor(ParameterExpression param) { + this._newParameter = param; + } + public Expression Replace(Expression exp) { + return this.Visit(exp); + } + protected override Expression VisitParameter(ParameterExpression node) { + return this._newParameter; + } + } +} \ No newline at end of file diff --git a/FreeSql/FreeSql.csproj b/FreeSql/FreeSql.csproj index 37ca9137..9b3c0cc3 100644 --- a/FreeSql/FreeSql.csproj +++ b/FreeSql/FreeSql.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.6.11 + 0.6.12 true YeXiangQin FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite. diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 2636dad9..9ce72c3a 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -2349,6 +2349,47 @@ + + + 使用 and 拼接两个 lambda 表达式 + + + + + + 使用 and 拼接两个 lambda 表达式 + + + + true 时生效 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + + true 时生效 + + + + + + 将 lambda 表达式取反 + + + + true 时生效 + + 生成类似Mongodb的ObjectId有序、不重复Guid diff --git a/Providers/FreeSql.Provider.MySql/FreeSql.Provider.MySql.csproj b/Providers/FreeSql.Provider.MySql/FreeSql.Provider.MySql.csproj index e27094b4..49f82402 100644 --- a/Providers/FreeSql.Provider.MySql/FreeSql.Provider.MySql.csproj +++ b/Providers/FreeSql.Provider.MySql/FreeSql.Provider.MySql.csproj @@ -2,7 +2,7 @@ netstandard2.0;net452 - 0.6.11 + 0.6.12 true YeXiangQin FreeSql 数据库实现,基于 MySql 5.6 diff --git a/Providers/FreeSql.Provider.MySqlConnector/FreeSql.Provider.MySqlConnector.csproj b/Providers/FreeSql.Provider.MySqlConnector/FreeSql.Provider.MySqlConnector.csproj index 5c4526ac..cdc59973 100644 --- a/Providers/FreeSql.Provider.MySqlConnector/FreeSql.Provider.MySqlConnector.csproj +++ b/Providers/FreeSql.Provider.MySqlConnector/FreeSql.Provider.MySqlConnector.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.6.11 + 0.6.12 true YeXiangQin FreeSql 数据库实现,基于 MySql 5.6 diff --git a/Providers/FreeSql.Provider.Oracle/FreeSql.Provider.Oracle.csproj b/Providers/FreeSql.Provider.Oracle/FreeSql.Provider.Oracle.csproj index d3155615..f4627275 100644 --- a/Providers/FreeSql.Provider.Oracle/FreeSql.Provider.Oracle.csproj +++ b/Providers/FreeSql.Provider.Oracle/FreeSql.Provider.Oracle.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.6.11 + 0.6.12 true YeXiangQin FreeSql 数据库实现,基于 Oracle 11 diff --git a/Providers/FreeSql.Provider.PostgreSQL/FreeSql.Provider.PostgreSQL.csproj b/Providers/FreeSql.Provider.PostgreSQL/FreeSql.Provider.PostgreSQL.csproj index d9e23606..1d129267 100644 --- a/Providers/FreeSql.Provider.PostgreSQL/FreeSql.Provider.PostgreSQL.csproj +++ b/Providers/FreeSql.Provider.PostgreSQL/FreeSql.Provider.PostgreSQL.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.6.11 + 0.6.12 true YeXiangQin FreeSql 数据库实现,基于 PostgreSQL 9.5 diff --git a/Providers/FreeSql.Provider.SqlServer/FreeSql.Provider.SqlServer.csproj b/Providers/FreeSql.Provider.SqlServer/FreeSql.Provider.SqlServer.csproj index 6a700bf8..74cc5afe 100644 --- a/Providers/FreeSql.Provider.SqlServer/FreeSql.Provider.SqlServer.csproj +++ b/Providers/FreeSql.Provider.SqlServer/FreeSql.Provider.SqlServer.csproj @@ -2,7 +2,7 @@ netstandard2.0;net451 - 0.6.11 + 0.6.12 true YeXiangQin FreeSql 数据库实现,基于 SqlServer 2005+,并根据版本适配分页方法:row_number 或 offset fetch next diff --git a/Providers/FreeSql.Provider.Sqlite/FreeSql.Provider.Sqlite.csproj b/Providers/FreeSql.Provider.Sqlite/FreeSql.Provider.Sqlite.csproj index 8bc42afb..48e33397 100644 --- a/Providers/FreeSql.Provider.Sqlite/FreeSql.Provider.Sqlite.csproj +++ b/Providers/FreeSql.Provider.Sqlite/FreeSql.Provider.Sqlite.csproj @@ -2,7 +2,7 @@ netstandard2.0;net45 - 0.6.11 + 0.6.12 true YeXiangQin FreeSql 数据库实现,基于 Sqlite 3.0