Translation: Getting Started with Entity Framework 6 of MVC5 (12)-Using advanced features for ASP.NET MVC applications

Use advanced features for ASP.NET MVC applications

This is a translation of Microsoft's official tutorial Getting Started with Entity Framework 6 Code First using MVC 5 series, here is the twelfth: Using advanced features for ASP.NET MVC applications

原文: Advanced Entity Framework 6 Scenarios for an MVC 5 Web Application


In the previous tutorial, you have implemented inheritance. This tutorial introduces the advanced features that can be used when you use the Entity Framework Code First to develop ASP.NET web applications, including the following parts:

  • Execute raw SQL query
  • Perform non-tracking queries
  • Check the SQL sent to the database

In addition, this tutorial provides a brief introduction to the following topics and provides reference links:

  • Warehousing and unit working mode
  • Agent class
  • Automatic change monitoring
  • Automatic verification
  • Visua Studio Entity Framework Tool
  • Entity framework source code

For most of the topics covered in this tutorial, you will use the web pages you have created and use the original SQL for batch updates. Then you will create a new page to update the credits of all courses in the database.

update course credits

Execute raw SQL query

The Entity Framework Code First API contains methods that allow you to send SQL commands directly to the database. You have the following options:

  • Use the DbSet.SqlQuery method to query and return the entity type. The returned object type must be the expected DbSet object, they will be automatically tracked by the database context. Unless you turn off tracking. (See the AsNoTracking method in the next section )

  • Use the Database.SqlQuery method to query and return non-entity types. The returned object will not be tracked by the database context, even if you use this method to retrieve the entity type.

  • Database.ExecuteSqlCommand is used for non-query type commands.

One of the advantages of using Entity Framework is that it allows you to implement a specific method of accessing data without having to manually input a lot of code. By automatically generating SQL queries and commands, you are freed from tedious manual coding. But in special cases, you may need to execute specific SQL queries that are created manually, these methods can achieve this function and provide you with exception handling.

When you frequently execute SQL commands in web applications, you must take the necessary precautions to protect your site from SQL injection attacks. One way is to use parameterized queries to ensure that strings from web pages are not interpreted as SQL commands. In this tutorial, when you use a user to enter a query, you will use a parameterized query.

Call a query to return the entity

DbSet<TEntity>The class provides a method that you can use to execute a query and return an entity type. To observe how this method works, you need to make some changes to the Details method in the Department controller.

In DepartmentController.cs, replace the Details method with the following code, highlighting the changes that need to be made:

public async Task<ActionResult> Details(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }

    // Commenting out original code to show how to use a raw SQL query.
    //Department department = await db.Departments.FindAsync(id);

    // Create and execute raw SQL query.
    string query = "SELECT * FROM Department WHERE DepartmentID = @p0";
    Department department = await db.Departments.SqlQuery(query, id).SingleOrDefaultAsync();

    if (department == null)
    {
        return HttpNotFound();
    }
    return View(department);
}

To verify that the new code is working properly, run the application, go to the department page and click the details of a department.

department

You can see everything is working as before.

Call a query to return other types of objects

In the earlier tutorial you created a student statistics grid to display the number of students registered on each registration date. This code uses LINQ to operate:

var data = from student in db.Students
           group student by student.EnrollmentDate into dateGroup
           select new EnrollmentDateGroup()
           {
               EnrollmentDate = dateGroup.Key,
               StudentCount = dateGroup.Count()
           };

Suppose you want to write SQL code directly for this query instead of using LINQ. You need to run a query to return objects other than entity types, which means you need to use the Database.SqlQuery method.

In HomeController.cs, replace the About method with the following code. The highlighted part shows the changes that need to be made:

public ActionResult About()
{
    // Commenting out LINQ to show how to do the same thing in SQL.
    //IQueryable<EnrollmentDateGroup> = from student in db.Students
    //           group student by student.EnrollmentDate into dateGroup
    //           select new EnrollmentDateGroup()
    //           {
    //               EnrollmentDate = dateGroup.Key,
    //               StudentCount = dateGroup.Count()
    //           };

    // SQL version of the above LINQ code.
    string query = "SELECT EnrollmentDate, COUNT(*) AS StudentCount "
        + "FROM Person "
        + "WHERE Discriminator = 'Student' "
        + "GROUP BY EnrollmentDate";
    IEnumerable<EnrollmentDateGroup> data = db.Database.SqlQuery<EnrollmentDateGroup>(query);

    return View(data.ToList());
}

Run the page, it will display the same data as before.

student body statistics

Call update query

Suppose the administrator wants to be able to perform batch operations on the database, such as changing credits for each course. If the school has a large number of courses, it is undoubtedly very inefficient to update each course separately. In this section you will implement a web page that enables users to modify the credits of all courses, and make this change by using the SQL Update statement, as shown below:

update course credits

In CourseController.cs, add the UpdateCourseCredits method of HttpGet and HttpPost:

public ActionResult UpdateCourseCredits()
{
    return View();
}

[HttpPost]
public ActionResult UpdateCourseCredits(int? multiplier)
{
    if (multiplier != null)
    {
        ViewBag.RowsAffected = db.Database.ExecuteSqlCommand("UPDATE Course SET Credits = Credits * {0}", multiplier);
    }
    return View();
}

When the controller processes the HttpGet request, ViewBag.RowsAffected will not return any value. The view will display an empty text box and a submit button.

When the update button is clicked, the HttpPost method is called to obtain the value entered in the text box. The code executes SQL to update the course and returns the number of affected rows in ViewBag.RowsAffected. When the view gets the value of the variable, it will display a message to explain the number of courses that have been updated instead of the text box and submit button, as shown in the following figure:

update course credits

In CourseController.cs, right-click the UpdateCourseCredits method and add a view:

add view

Use the following code to replace the view:

@model ContosoUniversity.Models.Course

@{
    ViewBag.Title = "UpdateCourseCredits";
}

<h2>Update Course Credits</h2>

@if (ViewBag.RowsAffected == null)
{
    using (Html.BeginForm())
    {
        <p>
            Enter a number to multiply every course's credits by: @Html.TextBox("multiplier")
        </p>
        <p>
            <input type="submit" value="Update" />
        </p>
    }
}
@if (ViewBag.RowsAffected != null)
{
    <p>
        Number of rows updated: @ViewBag.RowsAffected
    </p>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Run the application, add "/ UpdateCourseCredits" to the end of the browser address bar, such as Http: // localhost: xxxx / UpdateCourseCredits , open the page, and enter a number in the text box:

update course credits

Click Update and you will see the affected courses:

update course credits

Then return to the list, you will see that all courses have been updated:

courses

For more information on using raw SQL queries, see Raw SQL Queries on MSDN .

Non-tracking query

When the database context retrieves data rows and creates entity objects, by default it tracks whether the entities in memory are synchronized with the database. When you update an entity, the data in memory acts as a cache. This kind of caching is often unavailable in web applications, because context instances are usually short-lived (a new instance is created for each request), and the context is often destroyed after the entities have been read and used .

You can use the AsNoTracking method to disable tracking of entity objects in memory. In the following typical scenarios, you may need to do this:

  • A large amount of data needs to be retrieved, and turning off tracing may significantly improve performance.

  • You need to attach an entity to update it, but it is the same entity object previously obtained for different purposes. Because the entity is already tracked by the database context, you cannot attach the entity to make changes. In this case, you need to use the AsNoTracking option for earlier queries.

Check the SQL sent to the database

Sometimes, it is helpful to view the SQL queries that are actually sent to the database. In the earlier tutorial, you saw how to use the interceptor code to perform this job, and now you will see how to not use the interceptor method. To try this method, you will check a simple query and watch for additions such as pre-loading, filtering, and sorting to see what happened.

In CourseController.cs, replace the original with the following code to stop the preloading:

public ActionResult Index()
{
    var courses = db.Courses;
    var sql = courses.ToString();
    return View(courses.ToList());
}

Then set a breakpoint on the return statement, and press F5 to run the project in debug mode, select the course index page, when the code reaches the breakpoint, check the query variable, you will see the SQL query sent, it Is a simple select statement.

{SELECT 
[Extent1].[CourseID] AS [CourseID], 
[Extent1].[Title] AS [Title], 
[Extent1].[Credits] AS [Credits], 
[Extent1].[DepartmentID] AS [DepartmentID]
FROM [Course] AS [Extent1]}

You can use text visualization tools to view SQL in the monitoring window.

debug

Now a drop-down list is added to the course index page, which the user can use to filter specific departments. You will use the title to sort and specify the pre-loading of the navigation properties of the system.

In CourseController.cs, replace the Index method with the following code:

public ActionResult Index(int? SelectedDepartment)
{
    var departments = db.Departments.OrderBy(q => q.Name).ToList();
    ViewBag.SelectedDepartment = new SelectList(departments, "DepartmentID", "Name", SelectedDepartment);
    int departmentID = SelectedDepartment.GetValueOrDefault();

    IQueryable<Course> courses = db.Courses
        .Where(c => !SelectedDepartment.HasValue || c.DepartmentID == departmentID)
        .OrderBy(d => d.CourseID)
        .Include(d => d.Department);
    var sql = courses.ToString();
    return View(courses.ToList());
}

Still set a breakpoint on return.

This method receives the value selected in the drop-down list. If no item is selected, this parameter is null.

A SelectList collection containing all departments is passed to the drop-down list of views. The parameters passed to the SelectList constructor specify the value field name, text field name, and the selected item.

For the Get method of the course warehouse, the code specifies a filter expression for the Department navigation attribute, a sorting and lazy loading. If no item is selected in the drop-down table, the filter expression always returns true.

In Views \ Course \ Index.cshtml, before the table start tag, insert the following code to create the drop-down list and submit button:

@using (Html.BeginForm())
{
    <p>Select Department: @Html.DropDownList("SelectedDepartment","All")   
    <input type="submit" value="Filter" /></p>
}

Run the index page, continue to run when a breakpoint is encountered to display the page, select a department from the drop-down list and click filter:

courses

View the SQL statement according to the method just now, and you will see a SQL containing the inner join query:

SELECT 
    [Project1].[CourseID] AS [CourseID], 
    [Project1].[Title] AS [Title], 
    [Project1].[Credits] AS [Credits], 
    [Project1].[DepartmentID] AS [DepartmentID], 
    [Project1].[DepartmentID1] AS [DepartmentID1], 
    [Project1].[Name] AS [Name], 
    [Project1].[Budget] AS [Budget], 
    [Project1].[StartDate] AS [StartDate], 
    [Project1].[InstructorID] AS [InstructorID], 
    [Project1].[RowVersion] AS [RowVersion]
    FROM ( SELECT 
        [Extent1].[CourseID] AS [CourseID], 
        [Extent1].[Title] AS [Title], 
        [Extent1].[Credits] AS [Credits], 
        [Extent1].[DepartmentID] AS [DepartmentID], 
        [Extent2].[DepartmentID] AS [DepartmentID1], 
        [Extent2].[Name] AS [Name], 
        [Extent2].[Budget] AS [Budget], 
        [Extent2].[StartDate] AS [StartDate], 
        [Extent2].[InstructorID] AS [InstructorID], 
        [Extent2].[RowVersion] AS [RowVersion]
        FROM  [dbo].[Course] AS [Extent1]
        INNER JOIN [dbo].[Department] AS [Extent2] ON [Extent1].[DepartmentID] = [Extent2].[DepartmentID]
        WHERE @p__linq__0 IS NULL OR [Extent1].[DepartmentID] = @p__linq__1
    )  AS [Project1]
    ORDER BY [Project1].[CourseID] ASC

You can now see that the query above is a connected query that loads department and course data and contains a WHERE clause.

Remove thevar sql = conrses.ToString();

Warehousing and unit working mode

Many developers write code as packaging to implement the warehousing and unit working mode of the Entity Framework. These patterns create an abstraction layer between the business logic layer and the data access layer. Implementing these patterns can help your application isolate from changes in data storage and facilitate automated unit test development. However, writing additional code to implement these patterns for programs that use Entity Framework is not the best choice for several reasons:

  • The Entity Framework context class itself can isolate your code from the data storage of specific code.

  • When you use the Entity Framework, the Entity Framework context class for database update operations can be used as a unit of work class.

  • The functionality introduced in the Entity Framework 6 version allows it to be unit-test driven without writing warehousing code.

For detailed information on how to implement warehousing and unit working modes, please refer to the Entity Framework 5 version of this tutorial series . For how to execute unit test driver in Entity Framework 6 version, please refer to:

Agent class

When an entity instance is created by the Entity Framework (for example, when you execute a query), it always creates a proxy as a dynamically generated entity object derived from the entity. For example, in the following two debugger screenshots, in the first image, you see a student variable that is expected to be of type Student. After instantiating the entity, you will see the proxy class in the second image.

student controller

student controller

The proxy class rewrites some virtual attributes of the entity to insert hooks that automatically perform actions when accessing the attribute. One of the functions that uses this mechanism is lazy loading.

Most of the time you will not notice the agent, but there are exceptions:

  • In some cases, you may want to prevent the Entity Framework from creating proxy instances. For example, usually you want to serialize a POCO class entity, not a proxy class. One way to avoid serialization problems is to serialize data transfer objects (DTOs) instead of entity objects, such as Using Web API with Entity Framework . Another method is to disable proxy creation .

  • When you instantiate an entity class using the new operator, what you get is not a proxy instance. This means that you cannot gain capabilities such as lazy loading and automatic tracking. This is usually good: you generally do n’t need lazy loading because you need to create a new entity that does n’t exist in the database. When you explicitly mark an entity as Added, you usually do n’t need modification tracking. However, if you need lazy loading and you need to change tracking, you can create a new entity object through a proxy by using the Create method of the DbSet class .

  • You may want to get a real entity type from a proxy type. The GetObjectType method of the ObjectContext class can be used to obtain the actual entity type of the proxy type.

For more information, see Working with Proxies on MSDN .

Automatic change monitoring

The Entity Framework uses the comparison of the current value and the original value of an entity to determine whether an entity has been changed (and therefore needs to be sent to the database to perform updates). When an entity is queried or appended, the original value is saved. Some methods that lead to automatic change monitoring are as follows:

  • DbSet.Find
  • DbSet.Local
  • DbSet.Remove
  • DbSet.Add
  • DbSet.Attach
  • DbContext.Savechanges
  • DbContext.GetValidationErrors
  • DbContext.Entry
  • DbChangeTracker.Entries

If you are tracking a large number of entities, and you call these methods multiple times in a loop, you may temporarily turn off automatic change monitoring by using the AutoDetectChangesEnabled property to obtain program performance improvements.

Automatic verification

When you call the SaveChanges method, by default, the Entity Framework will verify all properties in all changed entities before updating to the database. If you update a large number of entities and have verified the data, this work is unnecessary, and you can get less processing time by turning off the verification temporarily. You can use the ValidateOnSaveEnabled property.

Entity Framework Power Tools

Entity Framework Power Tools is a simple VS extension that you can use to create the data model diagram shown in this tutorial. The tool can also do other tasks such as generating entity classes based on existing database tables when you use Code First. After installing the tool, you will see some additional options in the context menu. For example, when you right-click the context class of the Solution Explorer, you will get an option to generate a chart. You cannot modify the data model in the relationship diagram when you use Code First, but you can move the diagram to make it easier to understand.

solution  explorer

schoolContext

Entity framework source code

You can get the source code of Entity Framework 6 at http://entityframework.codeplex.com/ . In addition to the source code, you can generate, track problems, explore functions and more. You can submit bugs and contribute your own enhancements Entity framework source code.

Although the source code is open, the physical framework is a product fully supported by Microsoft. The Microsoft Entity Framework team will continue to receive feedback and test changes to ensure the quality of each version.

to sum up

In this way, a series of tutorials on using Entity Framework in ASP.NET MVC applications are all completed. For more information on how to use the Entity Framework, please refer to the EF documentation page on MSDN and ASP.NET Data Access-Recommended Resources .

For how to deploy it after you build the application, please refer to ASP.NET Web Deployment-Recommended Resources .

For more information about MVC, please refer to ASP.NET MVC-Recommended Resources .

Thanks

  • Tom Dykstra wrote the original version of this tutorial based on Entity Framework 5, and wrote the tutorial based on it. He is a senior programmer writer on the Microsoft Web platform and tools team.

  • Rick Anderson has done a lot of work in the Entity Framework 5 and MVC4 tutorials and co-authored the Entity Framework 6 update. He is a senior programmer writer for Microsoft Azure and MVC.

  • Rowan Miller and other Entity Framework teams reviewed the tutorial and debugged a large number of bugs.

author information

tom-dykstra Tom Dykstra -Tom Dykstra is a senior programmer and writer on the Microsoft Web Platform and Tools team.

Published 40 original articles · 25 praises · 100,000+ views

Guess you like

Origin blog.csdn.net/yym373872996/article/details/69668682