Мне нужно сгенерировать запросы SQL для различных поставщиков баз данных, для схем баз данных, которые не известны во время компиляции. Я вижу, что Entity Framework уже проделал тяжелую работу по предоставлению диалекта SQL под названием Entity SQL, который переводится на собственный SQL перед выполнением, и я надеялся каким-то образом воспользоваться этим.
В идеале я хотел бы просто сгенерировать ESQL, запустить его и получить IDataReader
, в то время как Entity Framework беспокоится о деталях поставщика. Однако, похоже, нет способа создать EntityConnection
без предоставления метаданных в виде файлов SSDL, CSDL и MSL, и я не буду узнавать о схеме базы данных до времени выполнения.
У меня вопрос: есть ли способ воспользоваться ESQL без какой-либо информации о схеме базы данных во время компиляции? Если необходимо (и возможно), я буду открыт для программного генерирования метаданных из базы данных и их кэширования. Я также был бы открыт для любых инструментов .NET, которые могли бы лучше соответствовать моим потребностям, чем Entity Framework.
Спасибо за ваше время.
Обновление
Благодаря предложению Алекса я смог разобраться, как генерировать метаданные, необходимые для EntityConnection
на лету, без записи каких-либо файлов. В результате я смог сделать именно то, на что надеялся. Теперь все, что мне нужно сделать, это выяснить, как извлечь информацию о доступных таблицах / представлениях для собственного использования из сгенерированных метаданных.
Вот мой тестовый код:
#r "System.Data.Entity"
#r "System.Data.Entity.Design"
#r "System.Transactions"
open System
open System.IO
open System.Data
open System.Data.EntityClient
open System.Data.Entity.Design
open System.Data.Mapping
open System.Data.Metadata.Edm
open System.Data.SqlClient
open System.Text
open System.Xml
let dbName = "Northwind"
let cnstr = sprintf "Server=.;Database=%s;Integrated Security=SSPI" dbName
let provider = "System.Data.SqlClient"
let mslText = StringBuilder()
let mslWriter = XmlWriter.Create(mslText)
let schemaGen = EntityStoreSchemaGenerator(provider, cnstr, dbName)
schemaGen.GenerateStoreMetadata() |> ignore
let modelGen = EntityModelSchemaGenerator(schemaGen.EntityContainer)
modelGen.GenerateMetadata() |> ignore
modelGen.WriteStorageMapping(mslWriter)
mslWriter.Close()
let mslReader = XmlReader.Create(new StringReader(mslText.ToString()))
let ssdlCollection = schemaGen.StoreItemCollection
let csdlCollection = modelGen.EdmItemCollection
let mslCollection = StorageMappingItemCollection(csdlCollection, ssdlCollection, [| mslReader |])
let mdw = MetadataWorkspace()
mdw.RegisterItemCollection(csdlCollection)
mdw.RegisterItemCollection(ssdlCollection)
mdw.RegisterItemCollection(mslCollection)
let sqlCn = new SqlConnection(cnstr)
let cn = new EntityConnection(mdw, sqlCn)
let cmd = cn.CreateCommand()
cmd.CommandText <- sprintf "SELECT p.ProductName FROM %sContext.Products AS p" dbName
cn.Open()
let reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)
while reader.Read() do
printfn "%A" reader.["ProductName"]
reader.Close()
cn.Close()
sqlCn.Close()