公么吃奶摸下面好舒服

发布日期:2022-06-18 17:03    点击次数:158

C#抒发式中的动态查询

当您使用LINQ来处理数据库时,这种体验是一种神奇的体验,对吗?你把数据库实体像一个庸碌的采集,使用Linq中像Where,Select无意 Take,这些绵薄的使用就能让代码可用了。

关联词,让咱们筹议一下这里是如何通过动态查询和抒发式树完结此功能的:幕后发生的事情。您编写的LINQ查询将交流为SQL(或其他方式),并将该SQL查询发送到数据库。然后将数据库的反应映射到C#对象。关联词,如何十足交流为SQL?

在本文中,您将看到诸如Entity Framework和MongoDB C#驱动门径之类的框架如何使用抒发式树进行交流。您将看到如何切身使用抒发式树来构建动态查询。这些查询是您无法在编译时创建的查询,因为您将廓清该查询仅在伊始时的外观。

对可查询树和抒发式树进行揭秘

筹议以下使用Entity Framework 6的C#代码:

SQL:SELECT     [Extent1].[StudentID] AS [StudentID],     [Extent1].[StudentName] AS [StudentName],     [Extent1].[DateOfBirth] AS [DateOfBirth],     FROM [dbo].[Students] AS [Extent1]     WHERE N'Billie' = [Extent1].[StudentName] 

请预防,WHERESQL查询中有一个操作。那不是很显明。要是SQL不包含WHERE,则扫数学生都将从数据库中带走,而且筛选将在.NET进度中本质。本色上,以下代码不错做到这少量:

//BAD: DbSet<Student> students = context.Students; Func<Student, bool> predicate = s => s.StudentName == "Billie"; var x = students.Where(predicate).ToList(); 

在临了一个示例中,SQL查询使扫数学生参加历程,并将其映射到惯例聚拢。不同之处在于,在第一段代码中, 性生大片免费观看网站精彩短片lambda是一个Expression

第二段代码在性能,内存和汇注方面很厄运。咱们从汇注中取得了好多对象,而不是仅从数据库中取得一个花样。然后,咱们使用CPU将它们序列化为C#对象。并用完内存将它们存储在进度的堆中。

因此,让咱们回到第一段代码。如何await students.Where(s => s.StudentName == "Billie").ToListAsync()产生一个包含的SQL查询WHERE N'Billie' = [Extent1].[StudentName]?

谜底是抒发树。该代码s => s.StudentName == "Billie"本色上是一个结构化查询,不错通过编程将其明白为节点树。在此示例中,有6个节点。最顶层的节点是lambda抒发式。左侧是lambda参数。在它的右边是Equal暗示抒发式的lambda主体。实体框架具有遍历这些抒发式树并构造SQL查询的算法。其他数据源提供门径(如Mongo DB C#驱动门径)也会发生相似的事情,除了它会构造一个MongoDB json查询。

C#抒发式树

在第一段代码中,类型s => s.StudentName == "Billie"为Expression

好的,关联词我该如何期骗它呢?

在通达阔情况下,公么吃奶摸下面好舒服使用抒发树的人们等于在构建寰球实体框架的人们。关联词在某些特定情况下,它变得额外有效。这是咱们最近在Ozcode[1](我的平方责任)中际遇的一个用例:

咱们想在名为Error的数据库实体上创建动态办事器端过滤。该实体具有好多属性,咱们但愿允许用户对其进行过滤。因此过滤应凭证被允许Username,Country,Version,或任何其他财产。这是咱们需要完结的API:

IQueryable<Error> _errors;  public IEnumerable<Error> GetErrors(string propertyToFilter, string value){ /*..*/}  

在这种情况下,propertyToFilter是的属性Error。使用惯例的LINQ,惟一的范例等于使用广阔的switch / case语句。有点像这么:

IQueryable<Error> _errors;  public IEnumerable<Error> GetErrors(string propertyToFilter, string value) {     switch (propertyToFilter)     {         case "Username":             return await _errors.Where(e=> e.Username == value).ToListAsync();         case "Country":             return await _errors.Where(e=> e.Country == value).ToListAsync();         case "Version":             return await _errors.Where(e=> e.Version == value).ToListAsync();         // ...             } } 

您可能会原意这不是遐想的聘用。除了必须编写扫数这些东西以外,它还额外容易出现失误。要是添加了属性若何办?要是重定名若何办?扫数这个词事情一团糟。

通过动态查询和抒发式树不错完结此功能的范例如下:

private async static Task<IEnumerable<Error>> GetErrors(string propertyToFilter, string value) {     var error = Expression.Parameter(typeof(Error));     var memberAccess = Expression.PropertyOrField(error, propertyToFilter);     var exprRight = Expression.Constant(value);     var equalExpr = Expression.Equal(memberAccess, exprRight);     Expression<Func<Error, bool>> lambda = Expression.Lambda<Func<Error, bool>>(equalExpr, error);      return await _errors.Where(lambda).ToListAsync(); } 

这里的每一转代码代表抒发式树中的一个节点。它们共同组成了最高节点-lambda。然后,不错在LINQ中使用动态抒发式,并生成办事器端SQL查询。我以为很好。

经管此问题的另一种范例是构建自界说SQL查询字符串。在Ozcode中,咱们使用的是MongoDB,因此SQL不合乎使用,但咱们不错创建一个自界说的MongoDB JSON查询字符串。也不是太难,关联词我以为抒发式树范例愈加天真和可靠。一方面,您不错将其放在LINQ中并与其他LINQ运算符组合。此外,当有诸如Entity Framework之类的经过测试的框架不错为您本质此操作时,为什么还要编写我方的查询。

节录

总结一下。这是本文中的一些要害点:

惯例函数/托付与抒发式之间的别离在于,抒发式不错用结构化树暗示。不错磨蹭地分析该树以创建诸如数据库查询之类的东西。 复旧抒发式的数据源完结该IQueryable接口。 要是您无法使用抒发式(以及使用惯例范例或托付),则查询将在办事器端而不在数据库端,这关于性能而言将是可怕的。 使用lambda(不带主体)时,抒发式是无缝创建的,因此这些年来您可能一直都在这么做。 您不错我方使用抒发式树来创建动态查询。这在无法在编译时仅在伊始时构建查询的情况下很有效。

References

[1] Ozcode: https://oz-code.com 

[2]: https://www.mediavine.com/





Powered by 东北女人毛多水多牲交视频 @2013-2022 RSS地图 HTML地图