GVKun编程网logo

c# – 为IQueryable创建自定义OrderByDescending()(c#生成唯一id)

13

在本文中,您将会了解到关于c#–为IQueryable创建自定义OrderByDescending()的新资讯,同时我们还将为您解释c#生成唯一id的相关在本文中,我们将带你探索c#–为IQuerya

在本文中,您将会了解到关于c# – 为IQueryable创建自定义OrderByDescending()的新资讯,同时我们还将为您解释c#生成唯一id的相关在本文中,我们将带你探索c# – 为IQueryable创建自定义OrderByDescending()的奥秘,分析c#生成唯一id的特点,并给出一些关于.NET Core - IEnumerable 与 IQueryable 中产生的不同空间/地理结果、.NET IQueryable OrderBy聚合字段、asp.net – System.Linq.Dynamic不支持OrderByDescending(“someColumn”)?、C# Entity Framework 中的 IQueryable 和 IQueryProvider 详解的实用技巧。

本文目录一览:

c# – 为IQueryable创建自定义OrderByDescending()(c#生成唯一id)

c# – 为IQueryable创建自定义OrderByDescending()(c#生成唯一id)

以下是我想要从高到低排序的值的一些示例.

8,929 viewers
18,213 viewers
2,223 viewers
41,231 viewers

这是我正在使用的查询的示例:

streams = streamRepository.FindAll()
                          .OrderByDescending(s => s.ViewCount)
                          .Take(4);

这是不正常的,因为我想它将参数作为字符串,而不是int,但这并不奇怪.

你如何建议我使用干净的C#/ Linq代码创建这个“订购”?

理想情况下,使用上面的数据示例,生成的有序集将是:

41,231 viewers
18,213 viewers
8,929 viewers
2,223 viewers

解决方法

也许不是最好的解决方案.但也许是这样的:

streamRepository.FindAll()
        .OrderByDescending(t => t =>Convert.Todouble(
                 t.ViewCount.Substring(0,t.ViewCount.IndexOf(' '))))

sql生成.不要那么可怕,它在linqpad中有效:

-- Region Parameters
DECLARE @p0 Int = 0
DECLARE @p1 NChar(1) = ' '
-- EndRegion
SELECT [t0].[SomeText]
FROM [Table1] AS [t0]
ORDER BY CONVERT(Float,SUBSTRING([t0].[SomeText],@p0 + 1,(CASE 
        WHEN (DATALENGTH(@p1) / 2) = 0 THEN 0
        ELSE CHARINDEX(@p1,[t0].[SomeText]) - 1
     END))) DESC

因为linq可以将substring和indexof转换为sql函数.但这也是格式特有的.就像在您的问题的评论中一样,我也建议您将列拆分为列.

.NET Core - IEnumerable 与 IQueryable 中产生的不同空间/地理结果

.NET Core - IEnumerable 与 IQueryable 中产生的不同空间/地理结果

如何解决.NET Core - IEnumerable 与 IQueryable 中产生的不同空间/地理结果?

我们将 ASP.NET Core 5 后端与 sql Server v15 和实体框架 V5 一起使用,有一些有趣的东西我一直在努力,考虑一下:

您有一张如下表格:

CREATE TABLE [dbo].[ContactDetails](
    [Id] [int] IDENTITY(1,1) NOT NULL,[Name] [nvarchar](128) NOT NULL,...
    [Geolocation] [geography] NULL
)

该表被其他表使用,例如。 Stores.,用于存储联系方式。

然后表 ContactDetails 会自动构建如下:

public partial class ContactDetail
{
    public ContactDetail()
    {
        Stores = new HashSet<Store>();
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public Geometry Geolocation { get; set; }
}    

然后你从输入中存储 Stores 的经度和纬度(双精度),比如:

Geometry Store.ContactDetails.Geolocation = new NetTopologySuite.Geometries.Point(store.longitude,store.latitude) { SRID = 4326 };

现在给定一个用户的位置,它是用同样的方式创建的

Geometry userLocation = new NetTopologySuite.Geometries.Point(user.longitude,user.latitude) { SRID = 4326 };

您想知道每个 Store 离用户有多远。你会怎么做?

我是这样做的:

DbContext dbContext; //...somehow constructed
var dbSet = dbContext.Set<Store>();
var distances = dbSet.Where(...).Select(store => store.ContactDetails.Geolocation.distance(userLocation));

但令我惊讶的是,距离完全消失了!我预计距离以度为单位返回,我将不得不将其转换为 Kms。但是这些数字完全不存在(比如 83130)。

所以我尝试了这个:

var anotherdistances = dbSet.Where(...).AsEnumerable().Select(store => store.ContactDetails.Geolocation.distance(userLocation));

这次的距离符合预期(例如 1.245 度)。

那里发生了什么? 我需要将结果保留为 IQueryable,以便我可以有效地进行进一步的过滤和转换。如何在不必将 IQueryable 转换为 IEnumerable 的情况下获得正确的距离?

我无法从其他问题中找到答案,我怀疑 Linq 无法将查询正确转换为 sql,并且 AsEnumerable() 之后的查询能够使用正确的类型推断并在加载时使用空间正确的方法内存中的对象。但这只是一些模糊的理解。如果您能帮助我理解这一点,我将不胜感激。

解决方法

您能否使用 IQuery<>.ToString() 来显示正在创建的实际 SQL 查询?也许这会为您指明正确的方向。另外,也许 this answer 很有趣。

此外,您可能需要查看您正在使用的数据库。根据{{​​3}}:

如果 EF Core 通过 SQL 对操作进行服务器评估,则结果为 单位由数据库决定。

,

好吧,谜团解开了。感谢 Dominik 的 @dominik-berse 建议,我进一步深入挖掘。

当查询从 LINQ 转换为 SQL 时,被映射的函数不必是等效的。在这种情况下,NetTopologySuite.Geometries.Distance() 被转换为 geography::STDistance() - 这取决于 SRID 模型的类型以不同的单位返回距离,在 4326 模型(由 GPS 使用)的情况下,它是米。>

当查询转换为对象时,将直接调用对象的方法,在本例中为 NetTopologySuite.Geometries.Distance()。

而且这两个值可以完全不同。

.NET IQueryable OrderBy聚合字段

.NET IQueryable OrderBy聚合字段

您需要先对聚合列进行投影,然后才能执行OrderBy。


    query = query.Select(x=>new {
    Item = x,Agg = x => string.Join(",",x.Values.Select(v => v.Name))
    }).OrderBy(a=>a.Agg).Select(a=>a.Item)

asp.net – System.Linq.Dynamic不支持OrderByDescending(“someColumn”)?

asp.net – System.Linq.Dynamic不支持OrderByDescending(“someColumn”)?

好吧,在我们的项目中,我正在使用System.Linq.Dynamic库,但我只是注意到我无法完成以下操作:

myDataSource.OrderByDescending( “someColumnName”)

因为我收到以下错误:

重载解析失败,因为无法使用这些参数调用可访问的OrderByDescending …

似乎Library只支持OrderBy(“someColumnName”)。是否有这样的原因,如果我想按降序重新排序记录,我将如何绕过这个问题?我是否必须使用Reverse()例如OrderBy(“someColumnName”)。Reverse()?看起来像黑客……

任何建议将不胜感激…

解决方法

假设您正在使用Microsoft示例库中的DynamicQuery Helper文件(位于命名空间System.Linq.Dynamic中),那么在阅读源代码之后,您需要指定所需的顺序,如下所示:
myDataSource.OrderBy("someColumnName descending")

C# Entity Framework 中的 IQueryable 和 IQueryProvider 详解

C# Entity Framework 中的 IQueryable 和 IQueryProvider 详解

前言

      相信大家对 Entity Framework 一定不陌生,我相信其中 Linq To Sql 是其最大的亮点之一,但是我们一直使用到现在却不曾明白内部是如何实现的,今天我们就简单的介绍 IQueryable 和 IQueryProvider。

 IQueryable 接口

      我们先聊聊这个接口,因为我们在使用 EF 中经常看到 linq to sql 语句的返回类型是 IQueryable,我们可以看下这个接口的结构:

 

复制代码代码如下:

public interface IQueryable : IEnumerable
{
      Type ElementType { get; }
      Expression Expression { get; }
      IQueryProvider Provider { get; }
}

 

 

      或许会有人很奇怪,当我们在开发过程中使用这个接口的时候,提供的方法远远不止这么点,因为微软提供了强大的 Queryable 类,当然大家不要以为这个类是实现 IQueryable 然后实现了很多方法,如果是那样那些第三方库怎么自定义呢?所以 Queryable 只是一个静态类,对 IQueryable 接口进行了扩展,下面是笔者在.Net Reflector 截图中一部分:

       如果读者细心一点会发现 linq to sql 并不会导致实际的查询,只有当我们真正开始使用的时候才从数据库中开始查询数据。

IQueryProvider 接口

      如果我们调试的 EF 的话,会看到生成的 T-SQL 语句。T-SQL 就是根据表达式树分析从而得出的,而核心就是 IQueryProvider 接口,下面就是该接口的结构:

 

复制代码代码如下:

public interface IQueryProvider
{
        IQueryable CreateQuery(Expression expression);
        IQueryable<TElement> CreateQuery<TElement>(Expression expression);
        object Execute(Expression expression);
        TResult Execute<TResult>(Expression expression);
}

 

 

      其中 CreateQuery 就是负责解析表达式树的,当然还要将处理后的结果返回,以便接着分析下面的语句,当然这中间只是分析,你完全可以根据表达式树得出你自己需要的查询语句,比如 SQL 或者其他什么,只有在真正使用数据的时候才会调用 Execute 方法,这个时候就可以根据我们自己分析的语句开始进行实际的查询了。

 实例分析

QueryProvider 类

      光说不练我们永远不能明白其中的原理,所以下面我们就简单的举一个例子来展示下。首先我们先实现 IQueryProvider 接口,其中会用到一个 Query 类,这个类会在后面进行介绍,首先我们新建一个 QueryProvider 类实现 IQueryProvider 接口,首先我们看下 CreateQuery<S> 方法:

       这里的 expression 就是传递给我们,并且需要我们处理的表达式树,最后还要返回实现 IQueryable<S> 接口的示例,以便 LINQ 在此基础上进行下面的查询,这里我们仅仅只是创建了一个 Query 的实例,同时将 expression 传递给它,因为此处仅仅只是一个 DEMO,所以我们没有去真正解析表达式树(这其中要做的工作很多)。接着还有 CreateQuery 方法:

 我们可以看到下面这句话:

实际的含义就是创建 Query<> 的实例,并且泛型参数是 elementType,参数是 thisexpression

 最后就是 Execute 方法了,传递一个 Expression 参数,并获取最后的结果,笔者在这里直接是写死的值:

 Query 类

      仅仅只有 QueryProvider 还没用,我们还需要一个能够保存表达式树状态的类,当然也包括了我们解析表达式后的结果也可以保存在其中,这样我们在 IQueryProvider 的 Execute 方法中就可以根据我们解析的结果执行执行并返回结果了。

       这里我们可以看到 Query 的 Expression 值在创建这个实例时,如果没有传递 Expression 参数时该值就是:

       但是在后面的过程中 Query 中的 Expression 将是 QueryProvider 中的 expression 值。

       到此我们其实就完成了一个简单的示例了,我们就可以开始测试我们的成果了,笔者在利用如下的代码来测试:

      OK,我们开始看看是如何分析这句 LINQ 语句的。

       首先我们看下在一开始执行时 Query 中 Expression 的返回值(如下图):

      在获取到这个表达式后,就开始执行 Linq,首先执行的是 where item == 123。

 分析 Where item == 123

     接着我们 F5,就可以看到在 QueryProvider 中的 CreateQuery<S> 命中了,并且 Expression 参数如下图所示:

      我们看到里面的字符串是 Where(item => (item == 123)),通过这句话我们就可以明白其实 LINQ 中的 where 实质上就是利用 Where 方法,并传递给它对应的 lambda 表达式。分析完了 where 部分,下面就是 FirstOrDefault 部分了。

 分析 FirstOrDefault

      当执行到 FirstOrDefault 的时候我们可以查看 t 的值,会发现 t 实际上就是 QueryProvider 中 CreateQuery<S> 的返回值。

 

      接着我们开始执行下面 FirstOrDefault 方法,发现会再一次的去获取 Expression 的值,而此时 Expression 的值就是上面 CreateQuery<T> 传递给我们的参数 expression

      然后在将这个表达式树和由表达式树表示 FirstOrDefault 方法调用的值拼接起来,并调用 QueryProvider 中的 Execute<S> 方法,我们可以看到这个时候传递给我们的参数 expression 的值。

       至此一个简单的流程就结束了,最后就是返回笔者写死的 123 这个值了。

       通过上面这个例子我们基本了解了其工作的流程,下面我们将一步一步的分析我们这个 where item == 123,当然我们将会用到递归,所以请大家整理好自己的思路,一步一步的看如何从一个表达式树中分析这条语句。

 分析表达式树实战

      首先我们一个分析表达式树的方法,这个方法我们暂且放在 QueryProvider 中:

 

复制代码代码如下:

public void AnalysisExpression(Expression exp)
        {
            switch (exp.NodeType)
            {
                case ExpressionType.Call:
                    {
                        MethodCallExpression mce = exp as MethodCallExpression;
                        Console.WriteLine("The Method Is {0}", mce.Method.Name);
                        for (int i = 0; i < mce.Arguments.Count; i++)
                        {
                            AnalysisExpression(mce.Arguments[i]);
                        }
                    }
                    break;
                case ExpressionType.Quote:
                    {
                        UnaryExpression ue = exp as UnaryExpression;
                        AnalysisExpression(ue.Operand);
                    }
                    break;
                case ExpressionType.Lambda:
                    {
                        LambdaExpression le = exp as LambdaExpression;
                        AnalysisExpression(le.Body);
                    }
                    break;
                case ExpressionType.Equal:
                    {
                        BinaryExpression be = exp as BinaryExpression;
                        Console.WriteLine("The Method Is {0}", exp.NodeType.ToString());
                        AnalysisExpression(be.Left);
                        AnalysisExpression(be.Right);
                    }
                    break;
                case ExpressionType.Constant:
                    {
                        ConstantExpression ce = exp as ConstantExpression;
                        Console.WriteLine("The Value Type Is {0}", ce.Value.ToString());
                    }
                    break;
                case ExpressionType.Parameter:
                    {
                        ParameterExpression pe = exp as ParameterExpression;
                        Console.WriteLine("The Parameter Is {0}", pe.Name);
                    }
                    break;
                default:
                    {
                        Console.Write("UnKnow");
                    }
                    break;
            }
        }

 

 

并在 CreateQuery<S> 中调用这个方法

      然后我们可以开始运行测试了,为了能够让读者明白当前处理的表达式树,所以在下面的截图中将会包含 AnalysisExpression 中参数 exp 的值,这样可以便于读者区分当前处理的表达式树。

 PS:Expression 类型中的 NodeType 是非常重要的,因为传递给我们的都是父类 Expression 类型,而我们需要根据 NodeType 的转换成对应的子类,这样我们才能够获取到更详细的信息。

 ExpressionType.Call

      我们根据一开始的 exp 的 NodeType 进入到这个分支,因为 where 实质上就是 ss 调用 where 方法,所以我们通过将 exp 转换成对应的 MethodCallExpression 类型,这样我们就可以看到调用的方法名称了。

      当然调用一个方法必须要有参数,所以下面还需要循环 Arguments 去分析具体的参数,其中也包括调用这个方法的对象,自然我们首先是分析调用这个方法的对象,这里我们进行了第一次的递归调用,跳到了 ExpressionType.Constant。

 ExpressionType.Constant

      NodeType 为这个类型,我们就可以通过 ConstantExpression 类型来获取对应的参数,通过 Value 我们可以可以获取到调用 where 方法的对象,当然到这里就不会继续往下分析了。

 

    所以我们继续跳到之前的 for 循环,开始分析第二个参数,就是 item => item == 123 这个部分了。

 ExpressionType.Quote

      如果接触过 lambda 的人可能会认为类型应该是 Lambda,但实际上不会直接跳转到那,而是先跳转到 Quote,然后我们再把转换成 UnaryExpression 类型,然后再继续分析其中 Operand 属性,而这个属性的 NodeType 就是 Lambda 了。个人认为这个应该是区分 lambda 和普通的方法,因为 where 不仅仅可以接收 lambda 同时也可以是常规的方法,所以这里还需要这一层。

 ExpressionType.Lambda

跳转到这,大家就不会感觉奇怪了,这里为了简洁。笔者并没有分析参数,而是直接分析 Body 部分,因为这部分才是我们的关键。

 ExpressionType.Equal

      我们看到这个 lambda 很简单,就是一个相等比较,所以直接跳转到了 Equal,当然还有 And、Or 等对应的枚举,而到了这一步我们就可以直接分析 Left 和 Right,当然这里还有一个小插曲,就是在跳到这个枚举的时候我查看 exp 的类型时,实际上是 LogicalBinaryExpression 类型,并不是 BinaryExpression 类型,然后用 Reflector 查看了下,我就呵呵了。

       我当时还奇怪,怎么没有这个类型呢,最后才知道玩的是这一出。到此为止,我们继续分析这个相等操作的左右两边的参数吧。

首先分析的是左边参数 item。

 ExpressionType.Parameter

      Item 挑传到这,并将其转换成 ParameterExpression 类型,笔者在此仅仅只输出了参数的名称。

到这左边的参数分析完毕,我们开始分析右边的参数。

 ExpressionType.Constant

      我们可以轻松的想到对应的 Value 就是 123 了,到此整个表达式就分析完毕了。

 我们看看最后控制台的输出结果吧。

       在此笔者还要声明一个问题,就是我们应该去理解我们使用的各种库的原理,这样便于我们以后添加符合实际开发的一些功能,当然这并不是浪费时间。而是提高今后项目开发的时间,随着不断的积累,我们会发现很多重复的功能并不需要我们去重复写了,而节省下来的时间我们就可以做自己想做的事了,所以我们要做一个有思想的懒程序员。

 源码下载

您可能感兴趣的文章:
  • C# IQueryable 及 IEnumerable 区别解析
  • C# Lambda 表达式及 Lambda 表达式树的创建过程
  • C# 用表达式树构建动态查询的方法
  • C# 表达式树的基本用法讲解
  • C# 快速高效率复制对象(表达式树)
  • 浅谈 c# 表达式树 Expression 简单类型比较 demo
  • C# 表达式树 Expression Trees 的知识梳理
  • C# 之 Expression 表达式树实例
  • c# 反射表达式树模糊搜索示例
  • C# IQueryable<T> 揭开表达式树的神秘面纱

关于c# – 为IQueryable创建自定义OrderByDescending()c#生成唯一id的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于.NET Core - IEnumerable 与 IQueryable 中产生的不同空间/地理结果、.NET IQueryable OrderBy聚合字段、asp.net – System.Linq.Dynamic不支持OrderByDescending(“someColumn”)?、C# Entity Framework 中的 IQueryable 和 IQueryProvider 详解等相关知识的信息别忘了在本站进行查找喔。

本文标签: