Groovy 1.8 :: 应用 LINQ

发布于 2024-11-13 08:18:15 字数 2706 浏览 5 评论 0原文

更新 2011 年 8 月 31 日
纪尧姆·拉福格 (Guillaume Laforge) 几乎已经做到了:
http://gaelyk.appspot.com/tutorial/app-engine-shortcuts# query

看起来他正在执行 AST 转换来实现:

alias as Entity

位。很酷的东西,Groovy 1.8 + AST 转换 = JVM 上的 LINQ 式查询。据我所知,GL 的解决方案需要更多工作才能实现完整的查询功能(如子查询、使用(字段)语法连接等),但对于他的 Gaelyk 项目显然没有必要。

编辑

作为实现纯 LINQ 语法的解决方法,我决定定义别名。没什么大不了的,并且消除了可能需要复杂的 AST 转换才能实现的主要障碍。

因此,而不是:

from   c as Composite
join   t as Teams
...

我现在定义别名(注意:需要强制转换才能在字段上自动完成):

def(Teams t,Composite c,Schools s) = [Teams.new(),Composite.new(),Schools.new()]

并使用 from、join 等映射语法

from    c:Composite
join    t:Teams
...

。要解决问题 #2(请参阅下面的原文),请添加实例级别 getProperty每个 pogo 别名的方法(其范围仅限于调用它的 ORM 闭包,很好)。当我们构建 sql 语句时,我们只返回字符串属性名称。

[t,c,s].each{Object o-> o.metaClass.getProperty = { String k-> k } }

取得“良好”进展;-)

现在要弄清楚如何处理“=”,这很棘手,因为 set 属性是无效的。可能必须使用 eq、neq、gt 等,但实际上更喜欢文字符号,这样更接近 sql 的可读性。

如果有兴趣的话,LINQ 在幕后做了很多工作。 Jon Skeet(赞美他的名字)有一个很好的回复: LINQ 内部是如何工作的?

原创

一直在检查 LINQ,非常好印象深刻。

// LINQ example
var games =
    from t in Teams
    from g in t.Games
    where g.gameID = 212
    select new { g.gameDate,g.gameTime };


// Seeking Groovy Nirvana
latest { Integer teamID->
    from   c as Composite
    join   t as Teams
    join   s as Schools on ( schoolID = {
                     from   Teams
                     where  t.schoolID = s.schoolID } )

    where   t.teamID = "$teamID"
    select  c.location, c.gameType, s.schoolName
    group   c.gameID
    order   c.gameDate, c.gameTime
}

建议的 Groovy 版本编译得很好,如果我定义别名 c、t、s 及其相应的 POGO,我会在字段上获得强类型 IDE auocomplete,很好。然而,与 LINQ 相差甚远,除了查询本身之外,没有(可见的)变量定义,完全独立且强类型,哇。

好的,那么在 Groovy 中可以完成吗?我认为(希望)是的,但我挂在两个问题上:

1)如何在不定义的情况下隐式填充别名变量?目前,我正在重写 String 上的 asType() ,因此在“from c as Composite”中,c 被强制转换为 Composite。很好,但是 IDE“认为”在闭包范围内 undefined c 是一个字符串,因此 POGO 字段上没有自动完成;-(

2) 由于 #1 没有解决,我按照上面定义别名,这样我就可以得到自动完成。很好,被黑了(与 LINQ 相比),但确实有效。这里的问题是,在“select c.location,c.gameType ...”中,我希望不评估字段,而只是将“c.location”返回到ORM select方法,而不是null(这是它的默认值)。 getProperty() 应该在这里工作,但我需要它仅适用于从 ORM 范围调用时的 pogo 字段(例如 orm 字段特定方法,如 select、order、group 等)。有点迷失了,也许有一种方法可以注释 orm 方法,或者只通过 orm 方法调用调用“特殊”pogo getProperty(这是上面涅槃查询中闭包的委托)。

应该指出的是,我并不打算为 Groovy 创建一个全面的 LINQ,但我希望看到这一 LINQ 的特定子集发生。

UPDATE 8/31/2011
Guillaume Laforge has nearly done it:
http://gaelyk.appspot.com/tutorial/app-engine-shortcuts#query

Looks like he's doing an AST transform to pull off the:

alias as Entity

bit. Cool stuff, Groovy 1.8 + AST transform = LINQ-esque queries on the JVM. GL's solution needs more work as far as I can see to pull off full query capabilities (like sub queries, join using(field) syntax and the like), but for his Gaelyk project apparently not necessary.

EDIT

As a workaround to achieving pure LINQ syntax, I have decided to def the aliases. Not a huge deal, and removes a major hurdle that would likely require complex AST transforms to pull off.

So, instead of:

from   c as Composite
join   t as Teams
...

I now define the aliases (note: need to cast to get auto complete on fields):

def(Teams t,Composite c,Schools s) = [Teams.new(),Composite.new(),Schools.new()]

and use map syntax for from, join, etc.

from    c:Composite
join    t:Teams
...

To solve issue #2 (see original below), add instance level getProperty methods to each pogo alias (whose scope is limited to ORM closure in which it is called, nice). We just return the string property name as we're building an sql statement.

[t,c,s].each{Object o-> o.metaClass.getProperty = { String k-> k } }

Making "good" progress ;-)

Now to figure out what to do about "=", that is tricky since set property is void. May have to go with eq, neq, gt, etc. but would really prefer the literal symbols, makes for closer-to-sql readability.

If interested, LINQ is doing quite a bit behind the scenes. Jon Skeet (praise his name) has a nice SO reply:
How LINQ works internally?

ORIGINAL

Have been checking out LINQ, highly impressed.

// LINQ example
var games =
    from t in Teams
    from g in t.Games
    where g.gameID = 212
    select new { g.gameDate,g.gameTime };


// Seeking Groovy Nirvana
latest { Integer teamID->
    from   c as Composite
    join   t as Teams
    join   s as Schools on ( schoolID = {
                     from   Teams
                     where  t.schoolID = s.schoolID } )

    where   t.teamID = "$teamID"
    select  c.location, c.gameType, s.schoolName
    group   c.gameID
    order   c.gameDate, c.gameTime
}

The proposed Groovy version compiles fine and if I def the aliases c,t,s with their corresponding POGO, I get strong typed IDE auocomplete on fields, nice. However, nowhere near LINQ, where there are no (visible) variable definitions other than the query itself, totally self contained and strongly typed, wow.

OK, so can it be done in Groovy? I think (hope) yes, but am hung up on 2 issues:

1) How to implicitly populate alias variable without def'ing? Currently I am overriding asType() on String so in "from c as Composite", c gets cast to Composite. Great, but the IDE "thinks" that in closure scope undefined c is a string and thus no autocomplete on POGO fields ;-(

2) Since #1 is not solved, I am def'ing the aliases as per above so I can get autocomplete. Fine, hacked (compared to LINQ), but does the trick. Problem here is that in "select c.location, c.gameType...", I'd like the fields to not be evaluated but simply return "c.location" to the ORM select method, and not null (which is its default value). getProperty() should work here, but I need it to only apply to pogo fields when called from ORM scope (e.g. orm field specific methods like select, order, group, etc.). Bit lost there, perhaps there's a way to annotate orm methods, or only invoke "special" pogo getProperty via orm method calls (which is the closure's delegate in above nirvana query).

Should point out that I am not looking to create a comprehensive LINQ for Groovy, but this one particular subset of LINQ I would love to see happen.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

再可℃爱ぅ一点好了 2024-11-20 08:18:15

Guillaume 使用 AST 变换的最大原因之一是“=”的问题。即使您像 Groovy 中通常那样使用 == 进行比较,从为其调用的compareTo 方法中,您也无法区分 ==、!=、<=、>=、<、> 之间的区别;.在 Groovy 的后续版本中,有两种可能的途径正在讨论中。一种是对每个比较使用不同的方法,另一种是存储可以在运行时访问的最小 AST。这朝着 C# 的方向发展,是一个非常强大的工具。问题更多的是如何有效地做到这一点。

One of the biggest reasons for Guillaume to use an AST transform is because of the problem with "=". Even if you use == for the compare as normally done in Groovy, from the compareTo method that is called for it, you cannot make out a difference between ==, !=, <=, >=, <, >. There are two possible paths for this in later versions of Groovy that are in discussion. One is to use for each of those compares a different method, the other is to store a minimal AST which you can access at runtime. This goes in the direction of C# and is a quite powerful tool. The problem is more about how to do this efficiently.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文