F# - 具有多个返回值的密码查询
Posted
技术标签:
【中文标题】F# - 具有多个返回值的密码查询【英文标题】:F# - cypher query with multiple return values 【发布时间】:2014-04-01 11:35:19 【问题描述】:鉴于此查询(来自here)
let pAfollowers =
client.Cypher
.Match("n<-[:follows]-e")
.Where(fun n -> n.Twitter = "tA")
.Return<Person>("e")
.Results
.Select(fun x -> x.Name)
我想对其进行调整并让它返回打包在一起的多个值。 不确定该类型的外观:
let pAfollowers =
client.Cypher
.Match("n<-[r:follows]-e")
.Where(fun n -> n.Twitter = "tA")
.Return<???>("n, r, e")
其次,我想知道在CreateUnique
之后是否可以有一个返回语句。
我正在尝试调整此查询:
let knows target (details : Knows) source =
client.Cypher
.Match("(s:Person)", "(t:Person)")
.Where(fun s -> s.Twitter = source.Twitter)
.AndWhere(fun t -> t.Twitter = target.Twitter)
.CreateUnique("s-[:knows knowsData]->t")
.WithParam("knowsData", details)
.ExecuteWithoutResults()
让它返回 s
、t
和 details
。
【问题讨论】:
【参考方案1】:好吧,好消息/坏消息 - 虽然在实践中好与坏:(
先好:
您可以在 CreateUnique 之后返回,例如:
.CreateUnique("s-[:Knows knowsData]-t")
.WithParam("knowsData", details)
.Returns<???>( "s,t" )
.Results;
坏消息:
坏消息是您可能在 F# 中无法做到这一点。 Neo4jClient
要求您使用对象初始化器或匿名类型来转换数据,因此您可以尝试以下操作:
type FollowingResults = Follower : Person; Followed : Person;
let createExpression quotationExpression = LeafExpressionConverter.QuotationToLambdaExpression quotationExpression
let pAfollowers =
client.Cypher
.Match("n<-[:follows]-e")
.Where(fun n -> n.Twitter = "tA")
.Return(createExpression <@ Func<ICypherResultItem, ICypherResultItem, FollowingResults>(fun (e : Cypher.ICypherResultItem) (n : Cypher.ICypherResultItem) -> Follower = e.As<Person>(); Followed = n.As<Person>()) @>)
.Results
.Select(fun x -> x)
for follower in pAfollowers do
printfn "%s followed %s" follower.Follower.Name follower.Followed.Name
F# 编译器完全没有 问题。但是,Neo4jClient
将引发 Argument 异常并显示以下消息:
表达式必须构造为对象初始值设定项(例如:n => new MyResultType Foo = n.Bar )或匿名类型初始值设定项(例如:n => new Foo = n.Bar )、方法调用(例如:n => n.Count())或成员访问器(例如:n => n.As().Bar)。您不能提供代码块(例如:n => var a = n + 1; return a; )或使用带参数的构造函数(例如:n => new Foo(n))。
问题在于,F# 没有 有对象初始化器,也没有匿名类型,你可以为 ages 使用 F# 的东西,却一无所获,就像 C#无法识别 F# 初始化。
【讨论】:
"F# 没有对象初始化器" 如果我理解你的意思是正确的,那么它确实有。请参阅“在初始化时为属性赋值”here。 不得不说我很困惑。 在 F# 3.0 中,我们添加了 CLIMutableAttribute。如果将此属性附加到 F# 记录类型 ... ,则 F# 编译器会为该类型生成的 IL 发出默认构造函数和属性设置器(尽管这些功能不会暴露给 F# 代码) @987654322 @ @ildjarn & NoIdeaHowToFixThis - 我的意思是就 C# 代码(在 neo4jclient 库中)而言 - 这不是对象初始化程序(我真的不是 F# 开发人员 - 非常高兴(实际上很高兴)被证明是错误的)。问题在于 C# 库如何读取代码。它在功能上是等价的,但在反射类型时不相同 - 这是客户端所做的。 好的,谢谢。我懂了。我找不到解决方法。这个问题对我来说是一个表演终结者。想知道我是否应该关闭这个问题并提出一个关于在类似情况下使用LeafExpressionConverter.QuotationToLambdaExpression
的更通用的问题。
我不能再添加更多了 - 我已经尝试过使用结构体、F# 的初始化程序等,但我最后没有高兴 - 正如我所说 - 我不擅长 F#,所以你可以坚持看看 F# 大师是否可以提供帮助 - 但请记住 - 如果您提出在 neo4jclient 中使用它的想法的问题,您需要指定它将被 C# 库使用,这个要点:gist.github.com/cskardon/9935002 应该会有所帮助 - 如果你能得到F# 调用它并返回 true 你应该是好的。【参考方案2】:
我对双方都有一些好消息。此代码将使用元组编译得很好,并且可以与支持 F# 元组的修改后的 Neo4jClient 一起使用:https://github.com/n074v41l4bl34u/Neo4jClient 解决方案基于:https://fsharppowerpack.codeplex.com/workitem/4572
let knows target (details : Knows) source =
client.Cypher
.Match("(s:Person)", "(t:Person)")
.Where(fun s -> s.Twitter = source.Twitter)
.AndWhere(fun t -> t.Twitter = target.Twitter)
.CreateUnique("s-[:knows knowsData]->t")
.WithParam("knowsData", details)
.Return(fun s t -> s.As<Person>(),t.As<Person>())
let pAfollowers =
client.Cypher
.Match("n<-[:follows]-e")
.Where(fun n -> n.Twitter = "tA")
.Return(fun (e : Cypher.ICypherResultItem) n -> e.As<Person>().Name,n.As<Person>().Name)
在 fun 中使用多个参数时,可以省略“(e : Cypher.ICypherResultItem)”上的类型注释。
但是,当使用单个参数时,这摆脱了丑陋的 createExpression ) 语法。 详情请看本页底部:https://gist.github.com/cskardon/8300420
【讨论】:
这个有没有被迁移到master并且在包中可用? 根据github.com/Readify/Neo4jClient/commit/…,它已于 2014 年 5 月 26 日被拉回 master 分支,因此它应该可用。以上是关于F# - 具有多个返回值的密码查询的主要内容,如果未能解决你的问题,请参考以下文章