linq語法希望動態改變,想請問該怎麼做呢?

weixin_44220506 2021-02-23 09:59:21
我有一段如下的linq語法用來搜尋資料庫:


a => a.tdIsDelete != true && a.uStatus >= 0 && ((a.uLoginName != null && a.uLoginName.Contains(key)) || (a.uRealName != null && a.uRealName.Contains(key)))


其中,「uLoginName」及「uRealName」目前是or,但我希望依據用戶給予的參數來查詢。

例如:變數【bLoginName = true】而【變數bRealName=false】時,只確認uLoginName是否含包key,而不在乎uRealName是否有包含。

這時候我希望的linq語法如下:


a => a.tdIsDelete != true && a.uStatus >= 0 && ((a.uLoginName != null && a.uLoginName.Contains(key)))



請問我該怎麼做呢? 謝謝大家。
...全文
181 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
weixin_44220506 2021-02-26
  • 打赏
  • 举报
回复
感謝各位的回覆,目前選定linqKit來用,還挺好用的:)

預備結帖!!
跳动de指尖 2021-02-24
  • 打赏
  • 举报
回复
想了一下,可以用表达式树来实现

public enum ExpressComparison
{
	/// <summary>
	/// 等于
	/// </summary>
	Equal,
	/// <summary>
	/// 包含
	/// </summary>
	Contains,
	/// <summary>
	/// 不等于
	/// </summary>
	NoEqual,
	/// <summary>
	/// 大于
	/// </summary>
	Gt,
	/// <summary>
	/// 小于
	/// </summary>
	Lt,
	/// <summary>
	/// 大于或等于
	/// </summary>
	GtOrEqual,
	/// <summary>
	/// 小于或等于
	/// </summary>
	LtOrEqual,

	/// <summary>
	/// 自定义规则
	/// </summary>
	Custom
}
	
[AttributeUsage(AttributeTargets.Property)]
public class ViewModelLabelAttribute:Attribute
{
	public ExpressComparison Comparison { get; private set; }

	/// <summary>
	/// 生成表达式树,需要比较的方式
	/// </summary>
	/// <param name="expressComparison">比较方式</param>
	public ViewModelLabelAttribute(ExpressComparison expressComparison)
	{
		Comparison = expressComparison;
	}
}
定义比较的枚举和特性,然后是用反射和特性标注的方式来生成表达式树

public static class ExpressAction
{
	internal class QueryField
	{
		public ViewModelLabelAttribute Label { get; set; }

		public PropertyInfo Property { get; set; }

		public object Value { get; set; }

		internal Expression HandleField(ParameterExpression parameter)
		{
			if (Value == null) return Expression.Empty();
			if (Property.PropertyType.IsEnum && Convert.ToInt32(Value) == -1) 
				return Expression.Empty();
			var memberExpr = Expression.Property(parameter, Property);
			switch (Label.Comparison)
			{
				case ExpressComparison.Equal:
					return Expression.Equal(memberExpr, Expression.Constant(Value));
				case ExpressComparison.Gt:
					return Expression.GreaterThan(memberExpr, Expression.Constant(Value));
				case ExpressComparison.GtOrEqual:
					return Expression.GreaterThanOrEqual(memberExpr, Expression.Constant(Value));
				case ExpressComparison.Lt:
					return Expression.LessThan(memberExpr, Expression.Constant(Value));
				case ExpressComparison.LtOrEqual:
					return Expression.LessThanOrEqual(memberExpr, Expression.Constant(Value));
				case ExpressComparison.NoEqual:
					return Expression.NotEqual(memberExpr, Expression.Constant(Value));
				case ExpressComparison.Contains:
					if (Property.PropertyType == typeof(string) && Value is string)
					{
						var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
						if (containsMethod != null)
						{
							// return Expression.Call(memberExpr, containsMethod,
							//     Expression.Constant(Property.GetValue(null)), Expression.Constant(Value));
							return Expression.Call(memberExpr, containsMethod, Expression.Constant(Value));
						}
					}

					if (typeof(IEnumerable).IsAssignableFrom(Property.PropertyType))
					{
						var containsMethod = typeof(Enumerable)
							.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
							.FirstOrDefault(x =>
								x.Name == "Contains" && x.ReturnType == typeof(bool) &&
								x.GetParameters().Length == 2);

						if (containsMethod != null)
						{
							containsMethod = containsMethod.MakeGenericMethod(Value.GetType());
							return Expression.Call(containsMethod,  memberExpr,Expression.Constant(Value));
						}
					}
					
				case ExpressComparison.Custom:
					throw new NotImplementedException("暂无自定义实现");
				//..... 其他实现
			}

			return Expression.Empty();
		}



	}

	public static Expression<Func<TEntity, bool>> GenerateExpressTree<TEntity>(this TEntity entity) where TEntity : IBaseEntity, new()
	{
		var parameter = Expression.Parameter(typeof(TEntity), "__q");

		var queryFieldsExpression = (from x in entity.GetType().GetProperties()
									 let attr = x.GetCustomAttribute<ViewModelLabelAttribute>()
									 where attr != null
									 let field = new QueryField
									 {
										 Label = attr,
										 Property = typeof(TEntity).GetProperty(x.Name),
										 Value = x.GetValue(entity)
									 }
									 select field.HandleField(parameter)).Where(x => x.NodeType != ExpressionType.Default).ToList();

		var expression = (Expression)Expression.Constant(true);//(Expression)Expression.Equal(Expression.Constant(1), Expression.Constant(1));
		foreach (var expr in queryFieldsExpression)
		{
			if (queryFieldsExpression.IndexOf(expr) == 0)
			{
				expression = expr;
				continue;
			}
			expression = Expression.AndAlso(expression, expr);
		}
		return Expression.Lambda<Func<TEntity, bool>>(expression, parameter);
	}
}
单元测试通过,你可以尝试一下

public class VmUser : IBaseEntity
{
	//[ViewModelLabel(ExpressComparison.Equal)]
	public string Id { get; set; }

	[ViewModelLabel(ExpressComparison.Contains)]
	public string Name { get; set; }

	public string Avatar { get; set; }

	[ViewModelLabel(ExpressComparison.GtOrEqual)]
	public int Age { get; set; }

	[ViewModelLabel(ExpressComparison.Contains)]
	public string Groups { get; set; }
}

[TestMethod]
public void Lambda表达式树生成测试()
{
	var viewModel = new VmUser
	{
		Avatar = "http://localhost:9527/images/laola.png",
		Id = "dpangzi",
		Name = "d",
		Age = 30,
		Groups = "666"
	};
	var list = new List<UserTest>
	{
		new UserTest
		{
			Avatar = "http://localhost:9527/images/laola.png",
			Id = "dppangzi",
			Name = "跳动de指尖",
			Age = 30,
			Groups = new[] {"111", "222", "333"}
		},
		new UserTest
		{
			Avatar = "http://localhost:9527/images/laola.png",
			Id = "xxxxx",
			Name = "yyyyy",
			Age = 28,
			Groups = new[] {"444", "555", "666"}
		},
		new UserTest
		{
			Avatar = "http://localhost:9527/images/laola.png",
			Id = "zzzzz",
			Name = "qqqqq",
			Age = 18,
			Groups = new[] {"777", "888", "999"}
		}
	};	
	var expr = viewModel.GenerateExpressTree();
	var result = list.Where(expr.Compile()).ToList();
	Assert.IsTrue(result.Count > 0);
}


正怒月神 2021-02-23
  • 打赏
  • 举报
回复
Linq.Dynamic https://blog.csdn.net/xuchen_wang/article/details/90749743
  • 打赏
  • 举报
回复
使用LinqKit动态拼接linq var where= LinqKit.PredicateBuilder.New<>(a=>a.xx==""); if (xx) { where=where.And(a=>a.xx==""); }
weixin_44220506 2021-02-23
  • 打赏
  • 举报
回复
引用 1 楼 古耕 的回复:
a=> a.tdIsDelete != true && a.uStatus >= 0 && (((a.uLoginName != null && a.uLoginName.Contains(key)) && !(a.uRealName != null && a.uRealName.Contains(key)))?(a.uLoginName != null && a.uLoginName.Contains(key)):(a.uRealName != null && a.uRealName.Contains(key)))


謝謝您的回覆,很抱歉我沒有描述清楚問題,具體如下:

我有一個HTTP Get Method,其中keyword參數是用來對資料表欄位做關鍵字查詢,
而bLoginName和bRealName甚至bCreateTime…等參數是用來確認要不要針對這些欄位做查詢。

過去用ADO.NET可以自拼湊SQL語句,
但現在改用linQ不曉得該怎麼處理了,
再麻煩指導,謝謝了。
石岩Maple 2021-02-23
  • 打赏
  • 举报
回复
a=> a.tdIsDelete != true && a.uStatus >= 0 && (((a.uLoginName != null && a.uLoginName.Contains(key)) && !(a.uRealName != null && a.uRealName.Contains(key)))?(a.uLoginName != null && a.uLoginName.Contains(key)):(a.uRealName != null && a.uRealName.Contains(key)))

110,535

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧