F#类型提供者,如何更改数据库?

F#类型提供者,如何更改数据库?,f#,type-providers,F#,Type Providers,我使用F#TypeProviders处理来自两个不同服务器但很多数据库的SQL数据。它正在进行的很好,除了速度现在变得非常慢,因为我添加了更多的文件。到目前为止,每个文件都有自己的连接字符串。我正在考虑将连接字符串和类型提供程序提取到一个外部项目,该项目能够将数据库作为参数传递。为了实现这一点,我尝试以下内容,从以下链接中找到第三个答案: 现在,我需要为每个表(即每个表的类)执行此操作,随着文件的增长,编译和intellisense启动需要花费很长时间。您尝试采用的方法存在一个基本缺陷。您希望在

我使用F#TypeProviders处理来自两个不同服务器但很多数据库的SQL数据。它正在进行的很好,除了速度现在变得非常慢,因为我添加了更多的文件。到目前为止,每个文件都有自己的连接字符串。我正在考虑将连接字符串和类型提供程序提取到一个外部项目,该项目能够将数据库作为参数传递。为了实现这一点,我尝试以下内容,从以下链接中找到第三个答案:


现在,我需要为每个表(即每个表的类)执行此操作,随着文件的增长,编译和intellisense启动需要花费很长时间。

您尝试采用的方法存在一个基本缺陷。您希望在运行时从应用程序配置中获取连接字符串,并提供
SqlDataConnection
类型提供程序,使其对底层数据库具有魔力

但这种类型的提供程序在工作流的运行时阶段无法执行任何操作,因为它的工作必须在编译时在一些编译时已知的数据库上完成

然后,您可能会问,如果我们想使代码在编译一次之后能够在运行时配置数据库,那么使用类型提供程序有什么意义

是的,但我们确实希望类型提供程序工作的结果适用于结构相同的数据库,是吗

<> P>这样,提供类型提供程序在数据库<代码> COMPILTEMEDMEB/<代码>中执行它的工作,在编译时连接字符串<代码>编译时TimeCC/<代码>,并考虑在连接字符串上得到的所有GooDyes(类型检查,智能信息,…)<强>参数化< /强>。此连接字符串参数值
runTimeCC
可以在运行时以任何理想的方式进行设置,只要它指向与
compileTimeDB
具有相同模式的数据库
runTimeDB

下面用一段代码说明这一基本原则:

[<Literal>]
let compileTimeCC = @"Data Source=(localdb)\ProjectsV12;Initial Catalog=compileTimeDB;Integrated Security=True;"
.....
type MySqlConnection = SqlDataConnection<ConnectionString = compileTimeCC>
// Type provider is happy, let it help us writing our DB-related code
.....
let db = MySqlConnection.GetDataContext(runTimeCC)
// at run time db will be a runTimeDB set by connection string runTimeCC that can be any
// as long as runTimeDB and compileTimeDB has same schema
.....
然后,使用以下静态成员扩充每个遗留类型(下面为
OldPersonT1
给出,仅为简洁起见):

要使其正常工作,实时数据库可能与编译时数据库不同,它只应包含
OldPersonT1
拥有和依赖的所有内容。 同样,对于
OldPersonT2
或任何其他变体类型也是如此:通过实现每个变体类型一次
MakeModernPersons
,可以覆盖所有数据源实例

处理数据目的地需要一个带有签名的函数

let makeModernPersons destinationConnStr (source: IQueryable<ModernPerson>) =
...
让makeModernPersons destinationConnStr(来源:IQueryable)=
...
现在,只需操作两个实时连接字符串的值,就可以涵盖
Person
数据源和目标的所有可能组合


非常粗略,但想法似乎很清楚。

这可能有助于问题中的代码通过使用单独的非类型连接进行插入来更新复杂的内容;相反,使用source=sourceDB.GetDataContext(conStr)并从LINQ执行插入操作将消除大约70%的代码。或者,如果您出于某些原因不喜欢LINQ,并且您处于Sql2012或更高的领域,请切换到优秀的类型提供程序并留在ADO world中。类型人员将确保类型完全相同。我确实检查了SqlClient,但无法将其用作在较低版本上运行。此外,一些数据非常陈旧,难以处理,因此非常有限。此外,数据会被发送到另一台服务器,
conStr
仅用于目的地。如果仔细观察,您会注意到
use source=sourceDB.GetDataContext
使用的源代码与make相同。来源和目的地也是不同的,大多数时候都是不同的。我知道类型提供程序达到这个级别,我只是想有一种方法可以更改数据库,或者至少基于连接加载所有模式,这样我就不必在每个类上重复所有这些。同时也可以使编译和智能感知更快。@zulq:您的注释有点与您的语句相矛盾:),所有模式(表、SP…)在编译器进程
type X=SqlDataConnection
时,在编译时只加载一次。你不能得到更多、更少或与
X
不同的东西,只能使用提供的类型和数据库的不同实例,在这些实例中生成的
X
类型会保留下来。我相信这对于优化来说有点运气不好。@zulq:不太好,你只需要重新组合一下现有的类型。请参阅我对原始问题的更新。
[<Literal>]
let compileTimeCC = @"Data Source=(localdb)\ProjectsV12;Initial Catalog=compileTimeDB;Integrated Security=True;"
.....
type MySqlConnection = SqlDataConnection<ConnectionString = compileTimeCC>
// Type provider is happy, let it help us writing our DB-related code
.....
let db = MySqlConnection.GetDataContext(runTimeCC)
// at run time db will be a runTimeDB set by connection string runTimeCC that can be any
// as long as runTimeDB and compileTimeDB has same schema
.....
type CTSqlConn = SqlDataConnection<ConnectionString = @"Data Source=(LocalDB)\Projectsv12;Initial Catalog=myCompileTimeDB;Integrated Security=True">

type OldPersonT1 = CTSqlConn.ServiceTypes.OldPersonT1 // just for brevity
type OldPersonT2 = CTSqlConn.ServiceTypes.OldPersonT2
type ModernPerson = CTSqlConn.ServiceTypes.ModernPerson
type CTSqlConn.ServiceTypes.OldPersonT1 with
    static member MakeModernPersons(rtConn: string) =
        let projection (old: OldPersonT1) =
            // Just a direct copy, but you may be very flexible in spreading verification
            // logic between query, projection, and even makeModernPersons function
            // that will be processing IQueryable<ModernPerson>
            let mp = ModernPerson()
                mp.Id <- old.Id
                mp.birthDate <- old.birthDate
                mp.firstName <- old.firstName 
                mp.lastName <- old.lastName 
                mp.dateCreated <- old.dateCreated
                mp 
        query {
            for oldPerson in (CTSqlConn.GetDataContext(rtConn)).OldPersonT1 do
            select (projection oldPerson)
        }
OldPersonT1.MakeModernPersons("real time connection string to any DB having OldPersonT1 table")
let makeModernPersons destinationConnStr (source: IQueryable<ModernPerson>) =
...