SqlEntityConnection (Entity Data Model) TypeProvider - f#

I am using the SqlEntityConnection (Entity Data Model) TypeProvider to connect to a SQL Server database that has a few tables and stored procedures.
#if INTERACTIVE
#r "System.Data"
#r "System.Data.Entity"
#r "FSharp.Data.TypeProviders"
#endif
open System.Data
open System.Data.Entity
open Microsoft.FSharp.Data.TypeProviders
// You can use Server Explorer to build your ConnectionString.
type internal SqlConnection = Microsoft.FSharp.Data.TypeProviders.SqlEntityConnection<ConnectionString = #"DataSource=server etc">
let internal db = SqlConnection.GetDataContext()
According to the documentation provided by a link in the template file - http://go.microsoft.com/fwlink/?LinkId=229210
"Get the data context, which is an object that contains the database tables as properties and the database stored procedures and functions as methods."
db should have the stored procedures in the database as methods. However, I can only see the tables in the database as properties of db.
What am I missing?

I think the documentation is incorrect. The SqlEntityConnection TP uses the tool edmgen.exe in the backend to do the actual codegen and heavy lifting, and from what I can tell that tool doesn't support including stored procedures as part of the generated proxy classes. Here's another SO question asking about exactly this, sadly no replies.
Running
edmgen.exe /mode:FullGeneration /connectionstring:"..." /language:CSharp /p:EdmTest
outputs various files, only one of which (the .ssdl file) contains any information about the stored procedures present in my DB.
The SqlDataConnection TP definitely does support stored procedures, in case that's a possible alternative for you.

Related

Entity Framework Core Database Table Valued Functions Mapping

I use EFCore 2.1 Database First approach. I'm pretty familiar with SQL syntax and prefer build queries myself rather then leave this work on EF. I use Table Valued and Scalar Functions for querying the database.
I found this for Scalar
https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-2.0#database-scalar-function-mapping
But unfortunately nothing about Table Functions.
Is there any way to force Visual Studio grab all Table Functions and Scalar Functions and Stored Procedures from SQL Server, when I run Scaffolding?
I was using LINQ to SQL dbml designer before. Everything was extremely simple with dbml. You drag from Server Explorer drop to dbml and boom, I can use SQL Function or SP like regular C# method.
Any chance to reproduce this in EFCore?
There's no reverse engineer (aka DbContext scaffolding) support for it, but you can use FromSql() to query using table-valued functions. See these docs.
var searchTerm = "EF Core";
var blogResults = db.Blogs.FromSql(
"SELECT * FROM dbo.SearchBlogs({0})",
searchTerm);
Source : https://www.allhandsontech.com/data-professional/entityframework/entity-framework-core-advanced-mapping/
Use HasDbFunction to do a mapping, refer Microsoft doc
It requires return types to be declared as Keyless entity using HasNoKeyMicrosoft doc
Configure EF Context to expose Db function
modelBuilder.HasDbFunction(typeof(SalesContext)
.GetMethod(nameof(NameAndTotalSpentByCustomer)))
.HasName("CustomerNameAndTotalSpent");
modelBuilder.Entity<CustWithTotalClass>().HasNoKey();
Invoke Db function in calling code
_context.NameAndTotalSpentByCustomer().Where(c=>c.TotalSpent>100).ToList();
Generated SQL
SELECT [c].[Name], [c].[TotalSpent]
FROM [dbo].[CustomerNameAndTotalSpent]() AS [c]
WHERE [c].[TotalSpent] > 100

Connect to SQL database without the SQL type provider?

In reference to this question, I need to share a connection string with coworkers without the connection string being pushed to our repository. Using the F# SQL type provider forces me to "hardcode" the connection string in my code. Although the workaround provided in the answer is promising, is there simply a way to connect to the dB without the type provider?
I already know the schema/structure of the dB; is there some other way I can connect?
One possibility is using the EdmxFile type provider:
#I "../packages/FSharp.Data.TypeProviders/lib/net40"
#r "System.Data.Entity"
#r "FSharp.Data.TypeProviders.dll"
open FSharp.Data.TypeProviders
type DB = EdmxFile<"MyDB.edmx">
let c = new DB.Model.ModelContainer("runtimeConnectionString")
query { for e in c.MyEntitySet do select e.Id }
You can create the EDMX file in Visual Studio (from an existing DB or from scratch) by adding a new "ADO.NET Entity Data Model" item to a C# project and then moving it to the F# project. The designer functionality is then still available in the F# project.
Within the same FSharp.Data.TypeProviders project there exist DBML file, SqlData and SqlEntity type providers. The latter two require compile time connection strings or names but also support offline schema caching. So you could add the cache file to source control and then change the connection string.
Another alternative would be to use any of the "live" type providers but point it to a source controlled MDF file:
let [<Literal>] LocalMDF =
"Server=.\SQLExpress;AttachDbFilename=.\MyDataFile.mdf;Database=dbname;Trusted_Connection=Yes;"
If you are interested in issuing plain SQL, have a look at the SQL Client type provider. It allows specifying the .config file used at design-time.
Apart from that, all "non-type-provider" (less convenient, less type-safe) standard .NET approaches can be used as well:
ORMs (EF, NHibernate, Dapper, ...)
Might require non-idiomatic, verbose F# to mimick C# classes
ADO.NET
Hand-Coding (SqlDataReader and associates)
...

How to connect Active Reports 7 to use a stored procedures?

How to connect Active Reports 7 to use a stored procedures? I have stored procedures already written, but how do you connect to them to use the data in the tables so that my report is dynamic.
ActiveReports 7 has two different report types, with slightly different ways of using stored procedures.
If you are using a SectionReport (i.e. the traditional form of report that was available in ActiveReports 6) then you can execute a stored procedure via the EXEC SQL command in your query. f.e.
EXEC sp_mysp '<%myparameter%>'
In a PageReport (i.e. the new report type introduced in ActiveReports 7) then you need to set the command type to Stored Procedure and then the query string is set to the name of your stored procedure. If you have any parameters to pass then you can pass them in via the DataSet's parameters page.
In PageReports when working with the ADO.NET based data providers (SQL Server, OLE DB, and Oracle connection types) there is a 1-to-1 correlation between objects in the data source, data set, and parameters in Page Reports and what you see in the related ADO.NET *Connection, *Command, and *Parameter classes. So if you have questions about how those work you can just look at how you would write the same code with the ADO.NET classes.

Understanding VS's ability to create database on first run

I'm working with a (.net4 / mvc3 ) solution file downloaded (from a reputable source) where a connection string exists in web.config but I don't see explicit instructions to create the database and there's no included '.mdf'. The first time I build I got a runtime error regarding lack of permissions to CREATE database. So I created a blank db and made sure the string referenced a SQL user that had .dbo/owner rights to the db just created.
But subsequent builds don't seem to execute that same initialize db script - where ever that's stored.
Where is this 'first use' convention for creating databases documented?
thx
That is a feature of Entity Framework Code First. I am not sure what you are looking for exactly, but searching for "EF Code First Initialization Strategy" might help.
For instance read this article: EF Code First DB Initialization Using Web.Config
I assume you are talking about Entity Framework, which allows you to create the database from an instance of an ObjectContext object, which is used in any of the three approaches in EF (database-, model- and code-first).
Look for a line that actually calls ObjectContext.CreateDatabase(). If one of the supported ADO.NET provides is used (SQL Server or SQL Server CE 4.0) this will generate the required SQL Statements. Assuming the classic Northwind example, you might find something like that:
NorthwindContext context = new NorthwindContext();
if (!context.DatabaseExists())
{
context.CreateDatabase();
}
If this is in fact a code-first application, "lalibi" is right about the initialization strategy which by default doesn't require you to explicitly create the database. (But my guess is, that it actually uses a statement internally very similar to mine).

Extract query definition from JET database via ADO

I have a program in Delphi 2010 that uses a JET (mdb) database via ADO. I would like to be able to extract the definitions of some of the queries in the database and display them to the user. Is this possible either via SQL, some ADO interface, or by interrogating the database itself (I don't seem to have rights to MSysObjects).
Some of that information is available via ADOX calls. There is an overview of the api with some examples (unfortunately not in Delphi) on the MSDN website.
Basically what you will want to do is to is to import the ADOX type library, and then use the wrapper that is generated for you to access the underlying API. From there its as simple as navigating the hierarchy to get at the data you need.
You will need to access the specific View object, and from there get the command property.
Via DAO, it's pretty easy. You just extract the SQL property of each QueryDef. In DAO from within Access, that would be:
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Set db = DBEngine.OpenDatabase("[path/name of database]")
For Each qdf In db
Debug.Print qdf.SQL
Next qdf
Set qdf = Nothing
db.Close
Set db = Nothing
I don't know how to translate that, but I think it's the simplest method once you're comfortable with using DAO instead of ADOX.
I don't use ADO at all, but I'm guessing that it has a collection of views and the SQL property would work for SELECT queries. However, if you're interested in getting the SQL for all saved QueryDefs, you'd also need to look at the DML queries, so you'd have to look at the stored procedures. I would have to look up the syntax for that, but I'm pretty certain that's how you'd get to the information via ADO.

Resources