Setting values ​​when a user updates a record using Entity Framework 4 and VB.NET in an ASP.NET application

This is my first post, I hope that I follow the rules!

After a few weeks, having hit my head against brick walls and endless hours of Internet search, I decided that I needed to make my own post and, hopefully, find answers and recommendations from all your experts.

I am creating an ASP.NET application (in Visual Studio 2010) that uses a SQL 2008 database and Entity Framework 4 to combine two parts. First I created the database as a database project, and then created the Entity Model as a class project, which is then referenced in the main ASP.NET project. I believe this is called the First in Entity Framwork Database?

I am new to web applications (I mainly develop WinForms applications) and this is my first attempt to use Entity Framwork.

I can just understand C # so that any code samples or snippets you could provide would be preferable in VB, if possible.

To give some idea of ​​where I am still. I created a regsitration page called register.aspx and created a wizard style form using ASP: Wizard with ASP: TextBox, ASP: DropdownList and ASP: CheckBoxList, all of this are laid out inside an HTML table and use CSS for some formatting. As soon as the user receives the last page in the wizard and clicks “Finish”, I execute the code in the VB code behind the file as follows:

Protected Sub wizardRegister_FinishButtonClick(sender As Object, e As System.Web.UI.WebControls.WizardNavigationEventArgs) Handles wizardRegister.FinishButtonClick Dim context As New CPMModel.CPMEntities Dim person As New CPMModel.Person Dim employee As New CPMModel.Employee Dim newID As Guid = Guid.NewGuid With person .ID = newID .UserID = txbx_UserName.Text .Title = ddl_Title.SelectedValue .FirstName = txbx_FirstName.Text .MiddleInitial = txbx_MiddleInitial.Text .FamilyName = txbx_FamilyName.Text .Gender = ddl_Gender.SelectedValue .DOB = txbx_DOB.Text .RegistrationDate = Date.Now .RegistrationMethod = "W" .ContactMethodID = New Guid(ddl_ContactMethodList.SelectedValue) .UserName = txbx_UserName.Text If Not (My.Settings.AuthenticationUsingAD) Then .Password = txbx_Password.Text ' [todo] write call to salted password hash function End If .IsRedundant = False .IsLocked = False End With context.AddToPeople(person) With employee .ID = newID .PayrollNumber = txbx_PayrollNumber.Text .JobTitle = txbx_JobTitle.Text .DepartmentID = ddl_DepartmentList.SelectedValue .OfficeNumber = txbx_OfficeNumber.Text .HomeNumber = txbx_HomeNumber.Text .MobileNumber = txbx_MobileNumber.Text .BleepNumber = txbx_BleepNumber.Text .OfficeEmail = txbx_OfficeEmail.Text .HomeEmail = txbx_HomeEmail.Text .IsRedundant = False .RedundantDate = Nothing '-------------------------- .FiledBy = Threading.Thread.CurrentPrincipal.Identity.Name .FiledLocation = My.Computer.Name .FiledDateTimeStamp = Date.Now '---------------------------- End With context.AddToEmployees(employee) context.SaveChanges() End Sub 

The above works fine, it seemed like a reasonable way to do this (remember I'm new to the Entity Framework) and gave me the results I was expecting.

I have another page called manage.aspx on this page - this is a tab control, each tab contains asp: DetailsView, which is bound to asp: EntityDataSource, I turned on updating in all entity data sources and on some I also turned on Insert, neither one of them did not delete.

If I create and run the application at this stage, everything works fine, you can click the "Edit" link, make changes, and then click "Update", and, of course, these updates will be displayed on the screen instantly, and the database has correct values.

Here's the problem, I need to intercept the update in the above code (bold bit), that there is a column FiledBy, FiledLocation and FiledDateTimeStamp in my database. I do not want to show these columns to the user viewing the ASP.NET page, but I want to update them when the user clicks on the update (if any changes were made). I tried to convert ASP: DetailsView to a template and then encode the HTML part with things like:

 <@# Eval(User.Name) #> 

I managed to get it to put the correct values ​​into the text fields in edit mode, but I had the following problems:

  • It was not saved in the database
  • I need to show text fields that I don't want to do

I read several other posts here and on other websites that you can override for the SaveChanges part of the Entity Framwork model, an example of which is given in the following code:

 public override int SaveChanges() { var entities = ChangeTracker.Entries<YourEntityType>() .Where(e => e.State == EntityState.Added) .Select(e => e.Entity); var currentDate = DateTime.Now; foreach(var entity in entities) { entity.Date = currentDate; } return base.SaveChanges(); } 

The problem is that although I understand the idea and can just transfer it to VB, I don’t know how to implement it. Where can I put the code? How do i call? and etc.

Ideally, I would like to find a solution that meets the following requirements:

  • Not overwritten if I had to restore / update the Entity Model
  • No need to copy and paste for each table in my model (most, but not all, have audit columns)
  • It can be used for other columns, for example, if the user makes a choice in the checklist, I can write some value to another column (not exposed to the user).

I correctly approach the display of data in may websites, I definitely consider the limitation of DataView and GridView, I was thinking about creating a form, such as a registration form in table tags, but not having an idea how to fill in text fields, etc. values ​​from the database and how to implement paging, since many of the tables are related to each other, although saving changes would be easy if I filled in the text fields in the table.

Thanks to everyone who offers support there.

Kevin.

So, now I came closer, but still did not work correctly. I used the following code to edit the value in the DetailsView in the Databound event. If you write the correct timestamp in a read-only text box, but does not return this value back to the database when you click the Refresh button of the DetailsView control.

 Protected Sub dv_Employee_DataBound(sender As Object, e As EventArgs) Handles dv_Employee.DataBound If dv_Employee.CurrentMode = DetailsViewMode.Edit Then For Each row In dv_Employee.Rows If row.Cells(0).Text = "FiledDateTimeStamp" Then row.Cells(1).Text = Date.Now() End If Next End If End Sub 
+4
source share
2 answers

I like the idea of ​​overriding the save changes method. Your context should be a partial class, so you just need to define another class marked as partial with the same name in the same namespace and add an override to it.

 Namespace CPMModel Partial Public Class CPMEntities ...Your override here End Class 

Since this is an override of the SaveChanges method by default, you do not need to make any changes to its call. You will need to find a way to access entity level properties.

Since this is a method that makes changes for all objects, you cannot access properties, as in your example, since the entity class does not define your specific properties. Therefore, you need to create partial classes for your entities and make them all implement an interface that defines the properties with which you would like to interact.

Create Interface:

 Interface IDate Property Date() as DateTime End Interface 

Create a partial class for each of your objects that implements the IDate interface. (The same rules apply to these partial classes, they must be marked partial, have the same name as the class that they distribute and live in the same namespace). Then in your SaveChanges override

 public override int SaveChanges() { var entities = ChangeTracker.Entries<Entity>() .Where(e => e.State == EntityState.Added) .Select(e => e.Entity); var currentDate = DateTime.Now; foreach(var entity in entities) { ***Now cast entity to type of IDate and set your value *** entity.Date = currentDate; } return base.SaveChanges(); } 

I do not write in Vb, so I left the syntax in C #.

This should meet all your requirements.

+1
source

Okay, so this is not quite the way I thought it would work, but it has infact to satisfy my needs. View!

What I did was write a protected sub in the file behind the aspx file.

 Protected Sub CustomEntityUpdate_Employee(sender As Object, e As EntityDataSourceChangingEventArgs) Dim emp As CPMModel.Employee = e.Entity ' Check if the entity state is modified and update auditing columns If emp.EntityState = EntityState.Modified Then emp.FiledDateTimeStamp = Date.Now() emp.FiledBy = Threading.Thread.CurrentPrincipal.Identity.Name emp.FiledLocation = My.Computer.Name End If End Sub 

Then on the aspx page, I edited the Entity data source code to call the above routine

 #nUpdating="CustomEntityUpdate_Employee" <asp:EntityDataSource ID="eds_Employee" runat="server" ConnectionString="name=CPMEntities" DefaultContainerName="CPMEntities" EnableFlattening="False" EnableUpdate="True" EntitySetName="Employees" AutoGenerateWhereClause="True" Where="" EntityTypeFilter="Employee" **OnUpdating="CustomEntityUpdate_Employee">** <WhereParameters> <asp:SessionParameter Name="ID" SessionField="UserID" /> </WhereParameters> </asp:EntityDataSource> 

Protected Sub checks to see if the object has been modified, and if it updates the entity audit columns with the values ​​I wanted.

This works, but it will certainly do a lot more code, I would ideally want it to pack this, possibly into a class, and just call sub from various aspx pages through the OnUpdating event and have a class value that the entity makes the call and processes all the logic is there.

0
source

Source: https://habr.com/ru/post/1440997/


All Articles