What\'s the right way to run a EF6 stored procedure (database-first) in async mode?
I read about ToListAsync()
but I don\'t see that available on stored pro
As per this workitem you would need to use SqlQueryAsync
. Feel free to upvote the work item on the EF Codeplex site.
To map stored procedures and start using it with out writing any initial code, this is how I did it.
create a new model with a new connection string that will generate the connection string automatically in the web.config
file where the connection string is at (if you use a current connection string it may no work when you test the function for the SP on the model browser).
map your table and the stored procedures (you can test the stored procedures in the model browser).
create classes that represents the attributes retrieved by each stored procedure e.g if your stored procedure returns three columns A,B,C, then the class must also have these three columns as attribute with the [key()] on top of the column that is going to be the PK
now create your controller with the class created and a new DbContext
then copy the information in the data context generated for the model and pasted in the new context that you generate when creating the controller.
when you want to use the store procedures they will be ready on the db.context because you paste their code on you new db-context that you create when the controller was crated.
NOTE: I hope this is not confusing but I can use the stored procedures with out typing any code, please ask me if you need sample code or screen shots, your new db-context will not over write after you created
This is the stored procedure I map
'--------------------------------------------------------------------------
' <auto-generated>
' This code was generated from a template.
'
' Manual changes to this file may cause unexpected behavior in your application.
' Manual changes to this file will be overwritten if the code is regenerated.
' </auto-generated>
'-----------------------------------------------------------------------
Imports System
Imports System.Collections.Generic
Partial Public Class phone_CurrentConferences_Result
Public Property AppointmentID As Integer
Public Property AppTitle As String
Public Property DateTime As Nullable(Of Date)
Public Property [Date] As String
Public Property Time As String
Public Property Company As String
Public Property Contact As String
Public Property Phone As String
Public Property Office As String
Public Property Lead_Director As String
Public Property TBD As Nullable(Of Boolean)
Public Property conference As String
End Class
This is the same model with a primary key
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel.DataAnnotations
Public Class Conferences
[Key]
Public Property AppointmentID As Integer
Public Property AppTitle As String
Public Property DateTime As Nullable(Of Date)
Public Property [Date] As String
Public Property Time As String
Public Property Company As String
Public Property Contact As String
Public Property Phone As String
Public Property Office As String
Public Property Lead_Director As String
Public Property TBD As Nullable(Of Boolean)
Public Property conference As String
End Class
This is the context generated by the EF
'--------------------------------------------------------------------------
' <auto-generated>
' This code was generated from a template.
'
' Manual changes to this file may cause unexpected behavior in your application.
' Manual changes to this file will be overwritten if the code is regenerated.
' </auto-generated>
'--------------------------------------------------------------------------
Imports System
Imports System.Data.Entity
Imports System.Data.Entity.Infrastructure
Imports System.Data.Entity.Core.Objects
Imports System.Linq
Partial Public Class DayMasterEntities
Inherits DbContext
Public Sub New()
MyBase.New("name=DayMasterEntities")
End Sub
Protected Overrides Sub OnModelCreating(modelBuilder As DbModelBuilder)
Throw New UnintentionalCodeFirstException()
End Sub
Public Overridable Function phone_CurrentConferences(number As String, [date] As Nullable(Of Date)) As ObjectResult(Of phone_CurrentConferences_Result)
Dim numberParameter As ObjectParameter = If(number IsNot Nothing, New ObjectParameter("number", number), New ObjectParameter("number", GetType(String)))
Dim dateParameter As ObjectParameter = If([date].HasValue, New ObjectParameter("date", [date]), New ObjectParameter("date", GetType(Date)))
Return DirectCast(Me, IObjectContextAdapter).ObjectContext.ExecuteFunction(Of phone_CurrentConferences_Result)("phone_CurrentConferences", numberParameter, dateParameter)
End Function
End Class
SO, when I create the controller I use the model with the <KEY()>
and I create my own context that will look like this
Imports System.Data.Entity
Imports System.Data.Entity.Infrastructure
Imports System.Data.Entity.Core.Objects
Namespace Models
Public Class DayMasterContext
Inherits DbContext
' You can add custom code to this file. Changes will not be overwritten.
'
' If you want Entity Framework to drop and regenerate your database
' automatically whenever you change your model schema, please use data migrations.
' For more information refer to the documentation:
' http://msdn.microsoft.com/en-us/data/jj591621.aspx
Public Sub New()
MyBase.New("name=DayMasterEntities")
End Sub
Protected Overrides Sub OnModelCreating(modelBuilder As DbModelBuilder)
Throw New UnintentionalCodeFirstException()
End Sub
Public Property Conferences As System.Data.Entity.DbSet(Of Conferences)
End Class
End Namespace
Then I copy the info in the context generated by the EF to my context
Imports System.Data.Entity
Imports System.Data.Entity.Infrastructure
Imports System.Data.Entity.Core.Objects
Namespace Models
Public Class DayMasterContext
Inherits DbContext
' You can add custom code to this file. Changes will not be overwritten.
'
' If you want Entity Framework to drop and regenerate your database
' automatically whenever you change your model schema, please use data migrations.
' For more information refer to the documentation:
' http://msdn.microsoft.com/en-us/data/jj591621.aspx
Public Sub New()
MyBase.New("name=DayMasterEntities")
End Sub
Protected Overrides Sub OnModelCreating(modelBuilder As DbModelBuilder)
Throw New UnintentionalCodeFirstException()
End Sub
Public Overridable Function phone_CurrentConferences(number As String, [date] As Nullable(Of Date)) As ObjectResult(Of phone_CurrentConferences_Result)
Dim numberParameter As ObjectParameter = If(number IsNot Nothing, New ObjectParameter("number", number), New ObjectParameter("number", GetType(String)))
Dim dateParameter As ObjectParameter = If([date].HasValue, New ObjectParameter("date", [date]), New ObjectParameter("date", GetType(Date)))
Return DirectCast(Me, IObjectContextAdapter).ObjectContext.ExecuteFunction(Of phone_CurrentConferences_Result)("phone_CurrentConferences", numberParameter, dateParameter)
End Function
Public Property Conferences As System.Data.Entity.DbSet(Of Conferences)
End Class
End Namespace
So, now you can use this context to query
entConferences(number As String, [date] As Nullable(Of Date)) As ObjectResult(Of phone_CurrentConferences_Result)
or to get a DBSet(of conferences)
Here is a controller I have created with this technique
Look where I call my stored procedure
Dim conferences = db.phone_CurrentConferences(phoneNumber, currentDate)
Imports System.Data
Imports System.Data.Entity
Imports System.Data.Entity.Infrastructure
Imports System.Linq
Imports System.Net
Imports System.Net.Http
Imports System.Web.Http
Imports System.Web.Http.Description
Imports BIWEBAPI
Imports BIWEBAPI.Models
Namespace Controllers.DayMasterControllers
Public Class ConferencesController
Inherits System.Web.Http.ApiController
Private db As New DayMasterContext
' GET: api/Conferences
Function GetConferences() As IQueryable(Of Conferences)
Return db.Conferences
End Function
' GET: api/Conferences/3053742500
''' <summary>
''' Use to get the current conferences selected by date
''' </summary>
''' <param name="id">phone number and date separated by coma ",""</param>
''' <returns>conferences by date</returns>
''' <remarks></remarks>
<ResponseType(GetType(Conferences))>
Function GetConferences(ByVal id As String) As List(Of Conferences)
Dim conferencelist = New List(Of Conferences)
Dim dateAndPhoneNumber = Split(id, ",")
Dim currentDate = ""
Dim phoneNumber = dateAndPhoneNumber(0)
If dateAndPhoneNumber.Length > 1 Then
currentDate = DateTime.Parse(dateAndPhoneNumber(1))
Else : currentDate = DateTime.Today
End If
Dim conferences = db.phone_CurrentConferences(phoneNumber, currentDate)
For Each conferenceInQuery As Object In conferences
Dim conference = New Conferences()
conference.AppointmentID = conferenceInQuery.AppointmentID
conference.AppTitle = conferenceInQuery.AppTitle
conference.DateTime = conferenceInQuery.DateTime
conference.[Date] = conferenceInQuery.[Date]
conference.Time = conferenceInQuery.Time
conference.Company = conferenceInQuery.Company
conference.Contact = conferenceInQuery.Contact
conference.Phone = conferenceInQuery.Phone
conference.Office = conferenceInQuery.Office
conference.Lead_Director = conferenceInQuery.Lead_Director
conference.TBD = conferenceInQuery.TBD
conference.conference = conferenceInQuery.conference
conferencelist.Add(conference)
Next
Return conferencelist
End Function
' PUT: api/Conferences/5
<ResponseType(GetType(Void))>
Function PutConferences(ByVal id As Integer, ByVal conferences As Conferences) As IHttpActionResult
If Not ModelState.IsValid Then
Return BadRequest(ModelState)
End If
If Not id = conferences.AppointmentID Then
Return BadRequest()
End If
db.Entry(conferences).State = EntityState.Modified
Try
db.SaveChanges()
Catch ex As DbUpdateConcurrencyException
If Not (ConferencesExists(id)) Then
Return NotFound()
Else
Throw
End If
End Try
Return StatusCode(HttpStatusCode.NoContent)
End Function
' POST: api/Conferences
<ResponseType(GetType(Conferences))>
Function PostConferences(ByVal conferences As Conferences) As IHttpActionResult
If Not ModelState.IsValid Then
Return BadRequest(ModelState)
End If
db.Conferences.Add(conferences)
db.SaveChanges()
Return CreatedAtRoute("DefaultApi", New With {.id = conferences.AppointmentID}, conferences)
End Function
' DELETE: api/Conferences/5
<ResponseType(GetType(Conferences))>
Function DeleteConferences(ByVal id As Integer) As IHttpActionResult
Dim conferences As Conferences = db.Conferences.Find(id)
If IsNothing(conferences) Then
Return NotFound()
End If
db.Conferences.Remove(conferences)
db.SaveChanges()
Return Ok(conferences)
End Function
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If (disposing) Then
db.Dispose()
End If
MyBase.Dispose(disposing)
End Sub
Private Function ConferencesExists(ByVal id As Integer) As Boolean
Return db.Conferences.Count(Function(e) e.AppointmentID = id) > 0
End Function
End Class
End Namespace