EF6 Database First making Stored Procedure Async

后端 未结 2 1784
夕颜
夕颜 2021-01-22 20:24

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

相关标签:
2条回答
  • 2021-01-22 21:08

    As per this workitem you would need to use SqlQueryAsync. Feel free to upvote the work item on the EF Codeplex site.

    0 讨论(0)
  • 2021-01-22 21:10

    To map stored procedures and start using it with out writing any initial code, this is how I did it.

    1. 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).

    2. map your table and the stored procedures (you can test the stored procedures in the model browser).

    3. 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

    4. now create your controller with the class created and a new DbContext

    5. 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.

    6. 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

    0 讨论(0)
提交回复
热议问题