I am developing in an asp.net web site project. It does not have a very consistent data layer, so I am trying to implement code first entity framework.
I have recently discovered that the people who make entity framework have created a new version of EntityDataSource that works with Entity Framework 6.
This new datasource seems really good and it updates the database. It does not seem to call any of the methods on my DbContext class though.
As part of some basic change tracking requirements, I have overridden the DbContext SaveChanges() method and put some code in to update tracking fields on each record (CreatedBy,CreatedDate,ModifiedBy,ModifiedDate). The strange thing is that when I work with the DBContect directly, the SaveChanges() method is called. But when I use this EntityDataSource it does not call SaveChanges().
How does the Entity Framework EntityDataSource above go about updating the dbsets?
Is there any way I can make this EntityDataSource call the DbContext SaveChanges() method?
Is there an alternative to overriding the DBContext SaveChanges Method?
Here is an example of my entity framework EntityDataSource control definition
<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>
And Here is my DbContext (cut down). When update is called on the EntityDataSource, it does not pass through SaveChanges(). It does not even call the getter in the Applicants property to access the DBSet of Applicants. It still manages to save the information somehow!
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