首页 > 其他分享 >强大的动态 LINQ 库

强大的动态 LINQ 库

时间:2024-11-22 21:57:57浏览次数:1  
标签:Customers Name 强大 LINQ context var new 动态 Select

dynamic-linq.net,这个库大家都用过,简单说就是使用字符串编写查询表达式的,非常强大,因为字符串是可以运行时拼接的,所以就可以在运行时动态的构造查询,非常适合框架开发和需要灵活性的场景。
我用它解决了在原生代码非常困难且耗时(需要动态构造表达式)的功能,真正的直达痛点。
它dotnet下的命名空间是System.Linq.Dynamic.Core,现在就介绍下各种复杂的写法示例和注意事项。

1. IQueryable<>支持

//context是EFCore的DbContext
context.Customers.Where("City == \"Paris\"");
context.Customers.Where("City == @0 and Age > @1", "Paris", 50);
context.Customers.Select("new { City, CompanyName }");
context.Customers.OrderBy("City, CompanyName");
context.Customers.OrderBy("City, CompanyName desc");

2. IEnumerable<>支持

//list是IEnumerable<>类型
list.AsQueryable().Where("City == \"Paris\"");
list.AsQueryable().Where("City == @0 and Age > @1", "Paris", 50);
list.AsQueryable().Select("new { City, CompanyName }");
list.AsQueryable().OrderBy("City, CompanyName");
list.AsQueryable().OrderBy("City, CompanyName desc");

3. 参数用@符号加索引,如上文示例

4. 支持几乎所有的IQueryable扩展方法

如Where、Select、OrderBy、Any、Count、Join,参考 附1。

5. 类型转换

类型转换非常有用,可以对字符串类型的值转成你想要的类型,以满足更灵活场景的动态特性。
也支持复杂类型的转换,参考 附1中的Cast and OfType

//postgres数据库会转成: "Value"::int > 0
var count = qry.Count("As(Value, \"int?\") >0");

6. 复杂条件语句

简单的查询语句都很记住,复杂的查询条件也支持,下面的代码示例,User实体中有个叫Roles的集合导航属性,Role实体中有个Name字符串属性(数据库中对应Name字段),继续参考 附1。

var dynamicResult = context.Users.Where("Roles.Any(Name.Contains(@0))", search);

7. 支持dotnet中基本的常用写法

如 关键字、操作符、标识、常量、类型和System.Math、Convert等方法,全部区分大小写,如在C#下用true而不是True,是DateTime而不是datetime。
需要注意的地方:

  1. &&和and等效,||和or等效
  2. 字符需要单引号,字符串需要双引号,而不是按数据库中的语义
  3. Nullable同样也是类型后面加问号,如 int?
  4. it 很特殊,表示表达式的当前实例,如同下面表达式中的e:e=>e.....
  5. new(...)如同创建对象
  6. 数组也用小括号,如(1,3,9,22)
  7. T(...),这里的T是类型名,表示类型转换
  8. 其他语义如,iif、As和Is(应该不区分大小写)
  9. 支持数据库的常用操作符,如and、or、not、<>、in等

8. DynamicExpressionParser.ParseLambda

ParameterExpression x = Expression.Parameter(typeof(int), "x");
ParameterExpression y = Expression.Parameter(typeof(int), "y");
LambdaExpression e = DynamicExpressionParser.ParseLambda(new ParameterExpression[] { x, y }, null, "(x + y) * 2");
LambdaExpression e = DynamicExpressionParser.ParseLambda(new ParameterExpression[] { x, y }, typeof(double), "(x + y) * 2");
using (var context = new EntityContext())
{
    LambdaExpression e = DynamicExpressionParser.ParseLambda(
        typeof(Customer), typeof(bool),
        "City = @0 and Orders.Count >= @1",
        "London", 10);
}
using (var context = new EntityContext())
{
    var e1 = DynamicExpressionParser.ParseLambda<Customer, bool>(new ParsingConfig(), true, "City = @0", "London");
    var e2 = DynamicExpressionParser.ParseLambda<Customer, bool>(new ParsingConfig(), true, "c => c.CompanyName != \"test\"");

    var customers = context.Customers.ToList().AsQueryable().Where("@0(it) and @1(it)", e1, e2);
}
Expression<Func<Customer, bool>> e1 = c => c.City == "Paris";
var e2 = DynamicExpressionParser.ParseLambda<Customer, bool>(new ParsingConfig(), true, "c => c.CompanyName != \"test\"");

var customers = context.Customers.ToList().AsQueryable().Where("@0(it) and @1(it)", e1, e2);

9. Create Dynamic Class

public static Type CreateType([NotNull] IList<DynamicProperty> properties, bool createParameterCtor = true)
var props = new DynamicProperty[]
{
    new DynamicProperty("Name", typeof(string)),
    new DynamicProperty("Birthday", typeof(DateTime)) 
};

Type type = DynamicClassFactory.CreateType(props);

var dynamicClass = Activator.CreateInstance(type) as DynamicClass;
dynamicClass.SetDynamicPropertyValue("Name", "Albert");
dynamicClass.SetDynamicPropertyValue("Birthday", new DateTime(1879, 3, 14));

// Use the class here ...
Console.WriteLine(dynamicClass);

10. C# Eval Expression

以上动态linq的写法是完全免费的,但这个Eval.Execute和Eval.Compile是收费的(50个字符串以内免费)。
这也是一个很强大的功能,可能在一些特殊场景需要用到,但是需要注意的是,这个Eval会消耗大量的cpu并且性能会比较差。

int result = Eval.Execute<int>("X + Y", new { X = 1, Y = 2})

附1

转载自官网:https://dynamic-linq.net/basic-query-operators

Aggregate

var averagePrice = context.Orders.Aggregate("Average", "Price");
var maxAmount = context.Orders.Aggregate("Max", "Amount");
var minAmount = context.Orders.Aggregate("Min", "Amount");
var totalAmount = context.Orders.Aggregate("Sum", "Amount");

All

bool allHavePriceGreaterThan2 = context.Orders.All("Price > 2");
var search = "e";
var stronglyTypedResult = context.Users.Where(u => u.Roles.All(r => r.Name.Contains(search)));
var dynamicResult = context.Users.Where("Roles.All(Name.Contains(@0))", search);

Any

bool anyHavePriceGreaterThan7 = context.Orders.Any("Price > 7");
var search = "e";
var stronglyTypedResult = context.Users.Where(u => u.Roles.Any(r => r.Name.Contains(search)));
var dynamicResult = context.Users.Where("Roles.Any(Name.Contains(@0))", search);

Average

var averagePriceExample1 = context.Orders.Select("Price").Average();
var averagePriceExample2 = context.Orders.Average("Price");

AsEnumerable

var dynamicEnumerable = context.Orders.Select("Amount").AsEnumerable();

Cast and OfType

var ofTypeWorker = context.Employees.OfType(typeof(Worker));

// or

string boss = typeof(Boss).FullName;
var ofTypeBossA = context.Employees.OfType(boss);
var ofTypeBossB = context.Employees.OfType("Test.Models.Boss");

var allWorkers = context.Employees.OfType(typeof(Worker));
var castToWorkers = allWorkers.Cast(typeof(Worker));

var count = qry.Count("As(Value, \"int?\") != null");

Concat

var list1 = new List<string> { "User3", "User4" };
var list2 = new List<string> { "User5", "User6", "User7" };
var result = queryable.Select("@0.Concat(@1).ToList()", list1, list2);

Count

int numberOfOrdersWhichHavePriceGreaterThan2 = context.Orders.Count("Price > 2");
var usersWhoHaveTwoRoles = context.Users.Where("u => u.Roles.Count() == 2");

DefaultIfEmpty

var defaultIfEmpty = context.Customers.Where("Name == \"not-found\"").DefaultIfEmpty();

var users = context.Users.Select("Roles.Where(r => r.Name == \"Admin\").DefaultIfEmpty().FirstOrDefault()");

Distinct

IQueryable queryable = new[] { 1, 2, 2, 3 }.AsQueryable();
var distinctIntegerValues = queryable.Distinct();

var items = context.Customers
    .Include(c => c.Orders)
    .Select("new (Name as CustomerName, Orders.Distinct() as UniqueOrders)");

Except

var list1 = new List<string> { "User3", "User4" };
var list2 = new List<string> { "User3", "User6", "User7" };
var result = queryable.Select("@0.Except(@1).ToList()", list1, list2);

First, FirstOrDefault

var first = context.Customers.First("c => c.City == \"Paris\"");
var firstOrDefault = context.Customers.FirstOrDefault("c => c.City == \"Otherworld\"");

var items = context.Users
    .Include(u => u.Roles)
    .Select("new (Name as userName, Roles.FirstOrDefault().Name as roleName)")
    .ToDynamicList();

GroupBy

GroupBy by a single Key

var result = context.Posts.GroupBy("BlogId");

GroupBy by a composite Key

var result = context.Posts.GroupBy("new (BlogId, PostDate)").OrderBy("Key.PostDate");

GroupBy by a single Key and with a single result

var result = context.Posts.GroupBy("PostDate", "Title");

GroupBy by a single Key and a complex object result

var result = context.Posts.GroupBy("PostDate", "new (Title, Content)");

GroupBy by a single Key and do a count()

var result = context.Posts.GroupBy("BlogId").Select("new(Key, Count() AS Count)");

GroupBy by a single Key and do a sum()

var result = context.Posts.GroupBy("BlogId").Select("new(Key, Sum(NumberOfReads) AS TotalReads)");

GroupByMany

GroupByMany strongly typed extension

var sel = lst.AsQueryable().GroupByMany(x => x.Item1, x => x.Item2).ToList();

GroupByMany as a Dynamic LINQ string expression

var sel = lst.AsQueryable().GroupByMany("Item1", "Item2").ToList();

Intersect

var list1 = new List<string> { "User3", "User4" };
var list2 = new List<string> { "User5", "User6", "User7" };
var result = queryable.Select("@0.Intersect(@1).ToList()", list1, list2);

Join

var realQuery = persons.Join(
    pets,
    person => person,
    pet => pet.Owner,
    (person, pet) => new { OwnerName = person.Name, Pet = pet.Name }
);
var dynamicQuery = persons.AsQueryable().Join(
    pets,
    "it",
    "Owner",
    "new(outer.Name as OwnerName, inner.Name as Pet)"
);

Last, LastOrDefault

var last = context.Customers.First("c => c.City == \"Paris\"");
var firstOrDefault = context.Customers.LastOrDefault("c => c.City == \"Otherworld\"");

var items = context.Users
    .Include(u => u.Roles)
    .Select("new (Name as userName, Roles.LastOrDefault().Name as roleName)")
    .ToDynamicList();

Page, PageResult

var pagedCustomers = context.Customers.OrderBy("Name").Page(page, pageSize);
var result = context.Customers.OrderBy("Name").PageResult(page, pageSize);

public class PagedResult
{
    public IQueryable Queryable { get; set; }
    public int CurrentPage { get; set; }
    public int PageCount { get; set; }
    public int PageSize { get; set; }
    public int RowCount { get; set; }
}
public class PagedResult<TSource> : PagedResult
{
    public new IQueryable<TSource> Queryable { get; set; }
}

Reverse

var reversed = ((IQueryable) persons.AsQueryable()).Reverse();

SelectMany

Use SelectMany as ExtensionMethod

var result = context.Users.SelectMany("u => u.Roles.Select(r => r.Name)").ToDynamicArray();

Use SelectMany inside a Dynamic LINQ string and return a list of strings

var result = context.Users.SelectMany("Roles.SelectMany(Permissions)").Select("Name");

Use SelectMany on Generic Type

var result = context.Users.SelectMany<Permission>("Roles.SelectMany(Permissions)")

Use SelectMany with a Type

var result = context.Users.SelectMany(typeof(Permission), "Roles.SelectMany(Permissions)")

Skip, SkipWhile

var skipFirstCustomer = context.Customers.OrderBy("CustomerID").Skip(1);

var skipped = context.Customers.ToList().AsQueryable().SkipWhile("CompanyName != \"ZZZ\"");

Sum

var totalPriceExample1 = context.Orders.Select("Price * Amount").Sum();
var var totalPriceExample2 = context.Orders.Sum("Price * Amount");

Take, TakeWhile

var takeTwoCustomers = context.Customers.OrderBy("CustomerID").Take(2);

var takeWhile = context.Customers.ToList().AsQueryable().TakeWhile("CompanyName != \"ZZZ\"");

Union

var list1 = new List<string> { "User3", "User4" };
var list2 = new List<string> { "User5", "User6", "User7" };
var result = queryable.Select("@0.Union(@1).ToList()", list1, list2);

Async Query Operators

AllAsync、AnyAsync、AverageAsync、CountAsync、FirstAsync、FirstOrDefaultAsync、LastAsync、LastOrDefaultAsync、LongCountAsync、SingleOrDefaultAsync、SumAsync

标签:Customers,Name,强大,LINQ,context,var,new,动态,Select
From: https://www.cnblogs.com/pains/p/18563616

相关文章

  • SpringBoot实现轻量级动态定时任务管控及组件化
    关于动态定时任务关于在SpringBoot中使用定时任务,大部分都是直接使用SpringBoot的@Scheduled注解,如下:@ComponentpublicclassTestTask{@Scheduled(cron="0/5****?")//每5秒执行一次publicvoidexecute(){SimpleDateFormatdf=newSimpleDat......
  • 编程之路,从0开始:动态内存笔试题分析
        Hello大家好,很高兴我们又见面啦!    给生活添点passion,开始今天的编程之路。今天我们来看几个经典的动态内存笔试题。1、题目1#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<string.h>voidGetMemory(char*p){ p=(char*)malloc(100......
  • 动态内存管理
                         ......
  • MagicQuill,AI动态图像元素修改,AI绘图,需要40G的本地硬盘空间,12G显存可玩,Win11本地
    最近由magic-quill团队开源的MagicQuill项目十分引人瞩目,这个项目可以通过定制的gradio客户端针对不同的图像元素通过提示词进行修改,从而生成新的图像。值得一提的是,这个项目相当亲民,只需要20步迭代模型预测,甜品卡10秒钟就可以获取图片的修改效果,但是代价是至少需要40个G左......
  • JAVA 静态代理 & 动态代理
    Java中,代理模式是一种常见的设计模式,用于为某对象提供一种代理,以控制对该对象的访问。根据代理类的实现方式,可以分为静态代理和动态代理。以下将分别介绍这两种方式,并进行对比分析。静态代理静态代理是指在编译时期就已经确定了代理类的实现。代理类需要实现与目标对象相同的接......
  • MyBatis——#{} 和 ${} 的区别和动态 SQL
    1.#{}和${}的区别为了方便,接下来使用注解方式来演示:#{}的SQL语句中的参数是用过?来起到类似于占位符的作用,而${}是直接进行参数替换,这种直接替换的即时SQL就可能会出现一个问题当传入一个字符串时,就会发现SQL语句出错了:这里的zhangsan并不是作为一......
  • 动态规划部分题目代码记录
    A点击查看代码#include<iostream>#include<algorithm>usingnamespacestd;constintN=105;#definelllonglongllt,shu[N],n;intmain(){cin>>t;shu[1]=1;shu[0]=1;for(inti=2;i<82;i++)shu[i]=s......
  • 使用ENSP实现DHCP+动态路由
    一、项目拓扑   二、项目实现 (1)路由器AR1配置进入系统试图sys将路由器命名为R1sysnameR1关闭信息中心undoinfo-centerenable进入g0/0/0接口intg0/0/0将g0/0/0接口IP地址配置为12.12.12.1/30ipaddress12.12.12.130退出此视图quit创建valn......
  • 深入理解 Callable 和 Future:异步编程的强大工具
    在多线程编程中,Callable和Future提供了一种强大的方式来处理异步任务,它们解决了Runnable无法返回结果以及无法处理异常的问题。通过Callable和Future,你可以实现更加高效和灵活的线程管理。本篇博客将详细探讨Callable与Runnable的区别,Future的作用以及如何利用这......
  • 动态内存管理
    一:为什么要有动态内存分配?创建变量的本质是向内存申请空间。inta=10;————向内存中申请4个字节的空间来存放10这个整型数据。intarr[10];————在内存中申请一块连续的空间(40个字节)intmath[30];————如果只有20个人,会有10个整型的空间浪费。      ......