asp.net - Entity Framework 6 EntityDataSource 未在 DbContext 中调用 SaveChanges

标签 asp.net .net vb.net entity-framework

我正在开发一个 ASP.NET 网站项目。它没有非常一致的数据层,因此我尝试实现代码优先 Entity Framework 。

我最近发现制作 Entity Framework 的人创建了一个可与 Entity Framework 6 一起使用的新版本 EntityDataSource。

http://blogs.msdn.com/b/webdev/archive/2014/02/28/announcing-the-release-of-dynamic-data-provider-and-entitydatasource-control-for-entity-framework-6.aspx

这个新数据源看起来非常好并且它更新了数据库。但它似乎没有调用我的 DbContext 类上的任何方法。

作为一些基本更改跟踪要求的一部分,我重写了 DbContext SaveChanges() 方法并放入一些代码来更新每个记录上的跟踪字段(CreatedBy、CreatedDate、ModifiedBy、ModifiedDate)。奇怪的是,当我直接使用 DBContect 时,会调用 SaveChanges() 方法。但是当我使用这个 EntityDataSource 时,它​​不会调用 SaveChanges()。

上面的 Entity Framework EntityDataSource如何更新数据库集?

有什么方法可以让这个 EntityDataSource 调用 DbContext SaveChanges() 方法吗?

是否有替代方法可以覆盖 DBContext SaveChanges 方法?

这是我的 Entity Framework EntityDataSource控件定义的示例

<asp:ListView ID="FormView" runat="server" DataKeyNames="RecordId" DataSourceID="ApplicantDataSource" DefaultMode="Edit">
    <EditItemTemplate>
        <asp:TextBox runat="server" ID="SomeField" Text='<%# Bind("SomeField")%>' ></asp:TextBox>
    </EditItemTemplate>
</asp:ListView>

<ef:EntityDataSource runat="server" 
                     ID="ApplicantDataSource"
                     ContextTypeName="Organisation.Application.MyDbContext"
                     EntitySetName="Applicants"
                     Where="it.RecordId=@RecordId"
                     EnableUpdate="true">
    <WhereParameters>
        <asp:QueryStringParameter Name="RecordId" QueryStringField="RecordId" DbType="String" DefaultValue=""/>
    </WhereParameters>
</ef:EntityDataSource>

这是我的 DbContext(删减)。当对 EntityDataSource 调用 update 时,它​​不会通过 SaveChanges() 传递。它甚至不调用 Applicants 属性中的 getter 来访问 Applicants 的 DBSet。它仍然设法以某种方式保存信息!

Public Class MyDbContext
    Inherits DbContext

    Public Shared Sub MyDbContext()
        Database.SetInitializer(Of MyDbContext)(Nothing)
    End Sub

    Public Sub New()
        MyBase.New("Name=ConnectionString")
    End Sub

    Public Property Applicants() As DbSet(Of Applicant)

    Protected Overrides Sub OnModelCreating(modelBuilder As DbModelBuilder)

        modelBuilder.Conventions.Remove(Of PluralizingTableNameConvention)()

        MyBase.OnModelCreating(modelBuilder)
    End Sub

    Public Overrides Function SaveChanges() As Integer
        Try
            Dim entities = Me.ChangeTracker.Entries().Where(Function(x) TypeOf x.Entity Is MyBase AndAlso (x.State = EntityState.Added OrElse x.State = EntityState.Modified))
            Dim currentUsername As String

            If HttpContext.Current IsNot Nothing And HttpContext.Current.User IsNot Nothing Then
                currentUsername = HttpContext.Current.User.Identity.Name
            Else
                currentUsername = "System"
            End If

            For Each entity In entities
                If entity.State = EntityState.Added Then
                    DirectCast(entity.Entity, MyBase).CreatedDate = DateTime.Now
                    DirectCast(entity.Entity, MyBase).CreatedBy = currentUsername
                ElseIf entity.State = EntityState.Modified Then
                    entity.Property("CreatedBy").IsModified = False
                    entity.Property("CreatedDate").IsModified = False
                End If

                DirectCast(entity.Entity, MyBase).ModifiedDate = DateTime.Now
                DirectCast(entity.Entity, MyBase).ModifiedBy = currentUsername
            Next

            Return MyBase.SaveChanges()
        Catch ex As DbEntityValidationException
            ' Retrieve the error messages as a list of strings.
            Dim errorMessages = ex.EntityValidationErrors.SelectMany(Function(x) x.ValidationErrors).[Select](Function(x) x.ErrorMessage)

            ' Join the list to a single string.
            Dim fullErrorMessage = String.Join("; ", errorMessages)

            ' Combine the original exception message with the new one.
            Dim exceptionMessage = String.Concat(ex.Message, " The validation errors are: ", fullErrorMessage)

            ' Throw a new DbEntityValidationException with the improved exception message.
            Throw New DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors)
        End Try
    End Function

End Class

最佳答案

上面的 Entity Framework EntityDataSource如何更新数据库集?

EntityDataSource 使用底层 ObjectContext ,而不是 DbContext。这就是为什么您永远不会看到任何内容直接通过 DbContext 上的 SaveChanges() 重载。

有什么方法可以让这个 EntityDataSource 调用 DbContext SaveChanges() 方法吗?

是或否,您可以重载 Updating 方法,并且通过 EntityDataSourceChangingEventArgs 您可以访问 DbContext,然后调用它。不过,这对于您的所有观点都是必要的,但我没有找到一种方法可以轻松地集中这一点及其糟糕的设计(因此没有)。

protected void x_Updating(object sender, EntityDataSourceChangingEventArgs e) {
        e.Cancel = true;
        DbContext dbc = new DbContext(e.Context, true);
        new YourDbContext(dbc).SaveChanges();
    }

是否有替代方法来重写 DBContext SaveChanges 方法?

仅是我上面描述的内容。您可以挂接到 ObjectContext 并获取传递的事件,但当 context is created 时您需要它的实例。 (参见该事件)。然后您可以订阅SavingChanges事件作为您的 Hook ,尽管这比 DbContext 上的 SaveChanges 受到更多限制。如果您只想做

这里是一个关于如何连接的 Vb.Net 代码示例。如果语法错误,请不要向我开枪,我已经很久没有用 Vb 编写任何东西了。您可能需要在设计器中注册onContextCreated(aspx 代码)。

免责声明 - 我尚未测试下面的代码。它部分基于您的代码和 SavingChanges 中的示例代码。文档。

Protected Sub onContextCreated(ByVal sender As Object, ByVal args As EntityDataSourceContextCreatedEventArgs)
   AddHandler args.Context.SavingChanges, AddressOf context_SavingChanges
End Sub

Private Sub context_SavingChanges(ByVal sender As Object, ByVal e As EventArgs)
    Dim context As ObjectContext = TryCast(sender, ObjectContext)

    If context IsNot Nothing Then
        If HttpContext.Current IsNot Nothing And HttpContext.Current.User IsNot Nothing Then
            currentUsername = HttpContext.Current.User.Identity.Name
        Else
            currentUsername = "System"
        End If

        For Each entity As ObjectStateEntry In context.ObjectStateManager.GetObjectStateEntries(EntityState.Added Or EntityState.Modified)
            If entity.State = EntityState.Added Then
                DirectCast(entity.Entity, MyBase).CreatedDate = DateTime.Now
                DirectCast(entity.Entity, MyBase).CreatedBy = currentUsername
            ElseIf entity.State = EntityState.Modified Then
                entity.Property("CreatedBy").IsModified = False
                entity.Property("CreatedDate").IsModified = False
            End If

            DirectCast(entity.Entity, MyBase).ModifiedDate = DateTime.Now
            DirectCast(entity.Entity, MyBase).ModifiedBy = currentUsername
        Next
    End If
    
End Sub
<小时/>

部分答案来源:http://w3stack.org/question/how-can-i-override-dbcontext-savechanges-when-using-entitydatasource-and-database-generated-model-edmx-ef-5/

关于asp.net - Entity Framework 6 EntityDataSource 未在 DbContext 中调用 SaveChanges,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33435588/

相关文章:

asp.net - 在 asp.net 上重定向网站

c# - 使用 asp.net 中的 Web 服务的网站登录表单

asp.net - 我的字体不工作

c# - .Net 应用程序的默认线程模型

c# - 激活特定注册期间发生错误

.net - 在带有 Rhino.Mocks 的 VB.NET 2008 单元测试中使用 Lambda

asp.net - 如果是超链接,请转到外部站点

c# - 无法在我的WPF应用中复制内存

.net - 如何使用List.Sort和Comparison(of T)来降序/升序排序?

c# - 以编程方式更改屏幕色彩平衡