我正在学习类型提供程序,它看起来像是一个突破性的功能。但是,我无法设法使用 JsonProvider 反序列化 json,以便目标类型具有 Generic.Dictionary 属性。可以使用 Json.NET 来完成。这是代码:
type ByProv = JsonProvider<"""{"dict":{"A":1,"B":2}}""">
type ByHand(d:Dictionary<string,int>) =
member val dict = d with get,set
let text = """{"dict":{"C":3,"D":4}}"""
let newt = JsonConvert.DeserializeObject<ByHand> text
let prov = ByProv.Parse text
printfn "%A" newt.dict.["C"]
//Can only call statically inferred A or B (and it will throw at run-time)
printfn "%A" prov.Dict.A
Run Code Online (Sandbox Code Playgroud)
显然,dict被推断为记录类型,而不是Dictionary默认类型。这可以被覆盖吗?
我正在尝试将FSharp.Data示例转换为我正在处理的问题的解决方案,但我只是没有走得太远.
给定返回json的端点类似于:
{
Products:[{
Id:43,
Name:"hi"
},
{
Id:45,
Name:"other prod"
}
]
}
Run Code Online (Sandbox Code Playgroud)
如何加载数据然后只Id从实际的现有数据中获取数据?
我不明白如何"模式匹配"的可能性:
root.Products可能是不存在/空Id可能不存在namespace Printio
open System
open FSharp.Data
open FSharp.Data.JsonExtensions
module PrintioApi =
type ApiProducts = JsonProvider<"https://api.print.io/api/v/1/source/widget/products?recipeId=f255af6f-9614-4fe2-aa8b-1b77b936d9d6&countryCode=US">
let getProductIds url =
async {
let! json = ApiProducts.AsyncLoad url
let ids = match json with
| null -> [||]
| _ ->
match json.Products with
| null -> [||]
| _ -> Array.map (fun (x:ApiProducts.Product)-> x.Id) …Run Code Online (Sandbox Code Playgroud) 我正在使用FSharp-Data中的JSONProvider自动为我正在使用服务的示例响应消费的Web服务创建类型.
但是,当涉及到在服务中重用的类型时,我有点困惑,例如,有一个api方法返回X类型的单个项,而另一个返回X列表,依此类推.我真的必须为此生成多个定义,并不意味着我会为同一个东西重复类型吗?
所以,我想我真正想问的是,有没有办法从JSON样本生成的类型中创建复合类型?
我有以下代码:
open FSharp.Data
[<Literal>]
let connectionString = @"Data Source=(local)\SQLExpress;Integrated Security=SSPI;Database=SfagStage"
type InsertEnhet = SqlCommandProvider<"Sql\InsertEnhet.sql", connectionString>
let insertEnhet (enhet:Enhet) =
let cmd = new InsertEnhet() // <<--- This generates an error runtime
cmd.Execute(enhet.Navn, enhet.Enhetsnummer, enhet.LEIKode, enhet.Kommune, DateTime.Now)
Run Code Online (Sandbox Code Playgroud)
我创建命令的行是导致我认为缺少方法的原因。我认为重要的例外部分是:
System.MissingMethodException: Method not found: 'Void FSharp.Data.ISqlCommand Implementation..ctor(FSharp.Data.Connection, Int32, System.String, Boolean, System.Data.SqlClient.SqlParameter[], FSharp.Data.ResultType, FSharp.Data.ResultRank, Microsoft.FSharp.Core.FSharpFunc`2, System.String)'.
Run Code Online (Sandbox Code Playgroud) f# type-providers f#-data assembly-binding-redirect fsharp.sqlclient
这个问题来自于正在努力从R转换到F#的人.我完全承认我的方法可能是错的,所以我正在寻找F#这样做的方法.我有一种情况,我想迭代一组XML文件,解析它们,并提取几个值,以确定哪些需要进一步处理.我的自然倾向是映射XML数据数组,exampleData在这种情况下,使用RawDataProvider类型提供程序解析每个数据,最后为包含解析的XML,XML中的Status值和ItemId值的每个文件创建一个Map对象.
事实证明,F#中的Map类型与R中的List不同.R中的列表本质上是可以支持混合类型的哈希映射.看来F#中的Map类型不支持存储混合类型.我发现这在我的R工作中非常有用,我正在寻找合适的F#系列.
或者,我是否认为这一切都错了?这是我在R中处理数据的一种非常自然的方式,所以我希望有一种方法可以在F#中进行处理.假设我将进行进一步分析并向这些集合添加其他数据元素.
更新: 这似乎是一个简单的用例,必须有一种惯用的方式在F#中执行此操作,而无需为每个分析步骤定义记录类型.我已经更新了我的例子,以进一步说明我想要做的事情.我想返回我分析的Map对象数组:
type RawDataProvider = XmlProvider<"""<product Status="Good" ItemId="123" />""">
let exampleData = [| """<product Status="Good" ItemId="123" />"""; """<product Status="Bad" ItemId="456" />"""; """<product Status="Good" ItemId="789" />"""|]
let dataResult =
exampleData
|> Array.map(fun fileData -> RawDataProvider.Parse(fileData))
|> Array.map(fun xml -> Map.empty.Add("xml", xml).Add("Status", xml.Status).Add("ItemId", xml.ItemId))
|> Array.map(fun elem -> elem.["calc1Value"] = calc1 elem["itemId"])
|> Array.map(fun elem -> elem.["calc2"] = calc2 elem.["ItemId"] elem.["calc1Value"])
Run Code Online (Sandbox Code Playgroud) 我们有一个简单的 F# 控制台应用程序,它通过FSharp.Data Http.Request. 我们正在使用该customizeHttpRequest参数来尝试设置请求超时属性。我们的用法如下:
let response = Http.Request(
serviceEndpoint,
headers = requestHeaders,
body = requestBody,
silentHttpErrors = true,
customizeHttpRequest = (fun request -> request.Timeout <- 1000; request))
Run Code Online (Sandbox Code Playgroud)
我们观察到我们的自定义超时被忽略(即请求在 1 秒后不会超时,如本例所示)。System.Net.HttpWebRequest我们还观察到,在默认超时 100,000ms后,请求不会超时。
这里有问题吗,还是我们没有customizeHttpRequest正确使用参数?
有没有办法按表的列而不是按行进行迭代?API示例在行中有结算日期信息:
Settlement Day,Period,IMBALNGC,Offer Volume Bid Volume,Accepted Offer Vol,Accepted Bid Vol,UAOV,UABV,PAOV,PABV
2014-01-14,1,877.000,52378.500,-53779.500,348.200,-654.374,0.000,0.000,348.200,-654.374
2014-01-14,2,196.000,52598.000,-53559.500,349.601,-310.862,0.000,0.000,316.701,-310.862
2014-01-14,3,-190.000,52575.000,-53283.500,186.183,-2.426,0.000,0.000,162.767,-1.917
2014-01-14,4,-61.000,52576.000,-53454.500,18.000,-24.158,0.000,0.000,18.000,-24.158
Run Code Online (Sandbox Code Playgroud)
但是,如果结算日信息在列中,有没有一种方法可以执行类似于 API 示例的操作,如下所示:
let firstCol = mrktDepth.Columns|> Seq.head
let settlementDate = firstCol.``Settlement Day``
let acceptedBid = firstCol.``Accepted Bid Vol``
let acceptedOffer = firstCol.``Accepted Offer Vol``
Run Code Online (Sandbox Code Playgroud) 我的F#应用程序具有非常好的F#模型,充分利用了F#类型系统(联合,记录,元组和基元类型).我试图找出将这些数据类型保存到SQL-Server数据库的最佳方法.
让我们做出以下假设:
我想要持久化的中心实体是一个被称为的判别联盟,Task它有大约30个不同的联合案例,每个案例具有完全不同的属性(可能是其他的DU,记录或元组或原始类型),这使得使用矩形关系表格实施起来非常繁琐
我希望每周多次不断改进这些模型,CI会在提交后立即将我的应用程序部署到生产中.同样,使用常规表会使ALTER TABLE语句减慢我的开发和部署速度,并且会增加大量的认知过载,任何新开发人员都会在这个系统上遇到挑战
在进行模型演变后,我应该能够轻松地使用后台进程在线升级我的旧模型,或者从数据库中获取时,使用接近0的停机时间
我应该能够在任意深度查询这些模型,并且我已经接近一百万行来处理,并且这将继续增长.查询速度应该很快,最多为100毫秒
我需要使用SQL Server,因为此应用程序是较大系统的一小部分,我希望任何数据库操作都参与任何正在进行的数据库事务
TaskJSON这是我的第一次尝试 - 将所有内容存储为JSON,识别可查询值,使用SQL Server 2016的新JSON函数将它们存储在索引表中.SQL Server中的JSON函数非常快,但索引这些查询要求我使用持久+计算+索引列或索引视图.
烦恼:
非常难以进化模型,特别是如果我想要进化所有类型X的实例,这些实例可能出现在不同联合情况的不同深度.没有标准化的语言可以指出这些演变
JSON不区分十进制/浮点数/数字,这有时很难处理,我需要自定义格式化程序.小问题,没什么大不了的.
查询语言在任意深度都有些原始,并且这些查询没有索引,因此新查询几乎总是要求我创建计算列或更改索引视图.
将新的索引列添加到索引视图不是ONLINE操作并导致停机,并且很难在CI中自动化
在同一个表中使用PERSISTED COLUMNS有时会导致SQL Server在搜索/选择时没有真正使用它们,而是从头开始重新计算这些值(因为它在查询计划器中没有准确地计算出这个操作的成本)
TaskXML这是我目前的实施.
我编写了自己的自定义XML序列化程序,这使我很容易使用XQuery和SQL Server的xml数据类型列查询数据库
使用功能非常强大的XSLT,模型演变变得轻而易举
问题:
我对我的XML解决方案非常满意 - 我只需要一种方法来加快我的XML查询,我想在这一点上,我已经达到了SQL Server可以提供的极限.
还有其他方法我错过了F#社区试图能够持久保存非常丰富的F#数据模型吗?
我知道我可以通过序列化到一个字符串并返回到 json 提供程序类型。我更喜欢更清洁的解决方案。用户获得 JsonValue 并且可能希望使用使用 JsonProvider 的类型化版本是一个小型 http 框架。
就像是:
type Balance = JsonProvider<"""{"balance":100}""">
let value = JsonValue.parse<"""{"balance":100}""">
let typed = Balance.fromValue value
Run Code Online (Sandbox Code Playgroud) 我有一个库,我使用FSharp.Data'sJsonProvider从 JSON 文件构造类型。但是,当我在控制台应用程序中引用该项目并尝试访问生成的类型时,它不会编译,而是在控制台应用程序的目录中查找示例文件,产生如下错误
Cannot read sample JSON from 'sample.json': Could not find file 'C:\Some\Where\TheSolution\ConsoleApp\sample.json
Run Code Online (Sandbox Code Playgroud)
我真的必须将示例文件复制到每个引用项目中,还是必须将其添加为 DLL 才能使其正常工作,还是我做错了什么?