Original: Implementing Basic CRUD functionality with the Entity Framework in ASP. NET MVC Application
1. Modify views\student\details.cshtml:
@model contosouniversity.models.student@{viewbag.title = "Details";}<H2>Details</H2><Div> <h4>Student</h4> <HR/> <DLclass= "Dl-horizontal"> <DT>@Html. displaynamefor (model = model. LastName)</DT> <DD>@Html. displayfor (model = model. LastName)</DD> <DT>@Html. displaynamefor (model = model. Firstmidname)</DT> <DD>@Html. displayfor (model = model. Firstmidname)</DD> <DT>@Html. displaynamefor (model = model. EnrollmentDate)</DT> <DD>@Html. displayfor (model = model. EnrollmentDate)</DD> <DT>@Html. displaynamefor (model = model. enrollments)</DT> <DD> <Tableclass= "Table"> <TR> <th>Course Title</th> <th>Grade</th> </TR>@foreach (var item in model.enrollments) {<TR> <TD>@Html. displayfor (ModelItem = Item. Course.title)</TD> <TD>@Html. displayfor (ModelItem = Item. Grade)</TD> </TR> } </Table> </DD> </DL></Div><P>@Html. ActionLink ("edit", "edit", new {id = model.id}) | @Html. ActionLink ("Back to List", "Index")</P>
2. Modify the Controllers\studentcontroller.cs create:
[Httppost][validateantiforgerytoken] PublicActionResult Create ([Bind (Include ="LastName, Firstmidname, EnrollmentDate")]student Student) {Try { if(modelstate.isvalid) {db. Students.add (student); Db. SaveChanges (); returnRedirecttoaction ("Index"); } } Catch(dataexception/*Dex*/) { //Log the error (uncomment DEX variable name and add a line here to write a Log.Modelstate.addmodelerror ("","unable to save changes. Try again, and if the problem persists see your system administrator."); } returnView (student);}
ValidateAntiForgeryToken
The Cross-site property is used to prevent cross-site request forgery attacks (forgery), and in the view you need to add @Html. AntiForgeryToken () to implement this feature.
The Bind property is used to prevent incoming extra fields. In the bind attribute Include
, the parameter lists the field whitelist (whitelist), and theExclude parameter lists the field blacklist (blacklist). Using the include parameter is more secure because new fields are not automatically blacklisted when we add new fields to the entity.
On the edit page, we can first read the entity from the database and then callTryUpdateModel,传入明确被允许的字段列表来防止传入多余的字段。
Another way to prevent passing in extra fields is to use the view model , which contains only the fields that we want to update in the view model. When the MVC model is bound, we can use a tool like AutoMapper to copy the values from the view model to the entity instance. Then use DB for the entity instance. Entry, change its state to unchanged, and then include each field ("PropertyName") in the view model. ismodified) is set to true. This method can be used to create and edit pages.
The code for the views\student\create.cshtml page is similar to the details.cshtml page, and the difference isEditorFor和ValidationMessageFor取代了DisplayFor:
<class= "Form-group"> @Html. labelfor (model = model. LastName, new {@class = "Control-label col-md-2"}) <class= "Col-md-10" > @Html. editorfor (model = model. LastName) @Html. validationmessagefor (model = model. LastName) </div></div>
To run the project:
The error message comes from the default service-side (server-side) authentication:
if (modelstate.isvalid) { db. Students.add (student); Db. SaveChanges (); Return redirecttoaction ("Index"); }
3. Modify the controllers\studentcontroller.cs edit:
[HttpPost, ActionName ("Edit")][validateantiforgerytoken] PublicActionResult Editpost (int?ID) { if(id = =NULL) { return NewHttpstatuscoderesult (httpstatuscode.badrequest); } varStudenttoupdate =db. Students.find (ID); if(TryUpdateModel (Studenttoupdate,"", New string[] {"LastName","Firstmidname","enrollmentdate" })) { Try{db. SaveChanges (); returnRedirecttoaction ("Index"); } Catch(dataexception/*Dex*/) { //Log the error (uncomment DEX variable name and add a line here to write a Log.Modelstate.addmodelerror ("","unable to save changes. Try again, and if the problem persists, see your system administrator."); } } returnView (studenttoupdate);}
The modified code is a best practice for blocking incoming extra fields. The original code was automatically added to the scaffold, the bind attribute was added and the modified tag was added for the model bound entity, so the code is no longer recommended because the Bind property automatically cleans up the original values of fields not listed in the Include parameter. Future MVC scaffolding will be updated without the bind attribute being generated for the edit method.
The modified code gets the entity that already exists and updates the entity based on data calls entered by the user TryUpdateModel
. EF automatically adds modified tags to new entities. When the SaveChanges method is called, the modified tag causes EF to generate SQL to update the database. The method ignores concurrency conflicts, and all columns that include values that do not change will be updated (subsequent tutorials will show how to handle concurrency conflicts if we only want to update the specified column to set the entity to unchanged, and set the column that needs to be changed to modified).
The data context keeps track of whether the state of the entity in memory is consistent with the state of the corresponding row in the database, and the tracking information will determine whenSaveChanges被调用时产生什么样的动作。例如,当我们通过Add方法添加一个实体时,这个实体的状态将会标记为Added,当调用SaveChanges
放方式,数据库上下文将会调用INSERT命令。实体的状态列表:
Added
: The entity does not yet exist in the database, and the SaveChanges
method produces an INSERT statement.
Unchanged:SaveChanges
方法将不会产生任何动作。当我们从数据库中获取一个实体时,这是该实体的初始状态。
Modified
: Some or all of the columns of an entity are changed, and the SaveChanges
method produces an UPDATE statement.
Deleted
: The entity is marked for deletion, and the SaveChanges
method produces a DELETE statement.
Detached
: The entity is not tracked by the database context.
In a desktop application, the change in entity state is automatic. In the desktop nature of the program, change the value of a part of an entity's field, the state of the entity is automatically marked as Modified
. Then, when we call SaveChanges
, EF will generate only the SQL that has changed the field.
However, the nature of the disconnection (disconnected) of the Web application does not allow this continuous sequence (continuous sequence). When the page rendering is complete, the entities read by DbContext will be released. When HttpPost
Edit
called, the new request creates a new DbContext instance, so we must manually set the state of the entity to Modified
. When called SaveChanges
, EF will update all columns, and the database context cannot know which columns we are updating.
If we only want to update the columns that are actually changed, we need to save the original values in some way (such as a hidden Attach
field), then call the method, change the value of the entity to the new value, and then call SaveChanges
.
4. Modify the controllers\studentcontroller.cs Delete:
[HttpPost, ActionName ("Delete")] [Validateantiforgerytoken] PublicActionResult deleteconfirmed (intID) {Try{Student Student=db. Students.find (ID); Db. Students.remove (student); Db. SaveChanges (); } Catch(dataexception/*Dex*/) { //Log the error (uncomment DEX variable name and add a line here to write a Log. returnRedirecttoaction ("Delete",New{id = id, savechangeserror =true }); } returnRedirecttoaction ("Index"); }
To raise the performance of concurrent programs, we need to avoid unnecessary queries and replace the Find and remove methods above with the following code:
New Student () {ID == entitystate.deleted;
5. Close the database connection :
protected Override void Dispose (bool disposing) { db. Dispose (); Base . Dispose (disposing);}
The Controller base class implements the IDisposable
interface, so you can override the Dispose method to release the context instance.
6. Transaction :
The EF supports transactions by default if you modify multiple rows or tables at the same time and callSaveChanges,EF会保证这些修改同时执行成功或失败。
Translation [MVC 5 + EF 6] 2: Base additions and deletions (CRUD)