第4部分,含有資料庫和 ASP.NET CorePart 4, with a database and ASP.NET Core

作者:Rick AndersonJoe AudetteBy Rick Anderson and Joe Audette

RazorPagesMovieContext 物件會處理連線到資料庫和將 Movie 物件對應至資料庫記錄的工作。The RazorPagesMovieContext object handles the task of connecting to the database and mapping Movie objects to database records. Startup.csConfigureServices 方法中,以相依性插入容器登錄資料庫內容:The database context is registered with the Dependency Injection container in the ConfigureServices method in Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();

    services.AddDbContext<RazorPagesMovieContext>(options =>
      options.UseSqlServer(Configuration.GetConnectionString("RazorPagesMovieContext")));
}

ASP.NET Core 組態系統會讀取 ConnectionStringThe ASP.NET Core Configuration system reads the ConnectionString. 對於本機開發,它會從檔案中的appsettings.js取得連接字串。For local development, it gets the connection string from the appsettings.json file.

您的產生程式碼會有不同的資料庫 (Database={Database name}) 名稱值。The name value for the database (Database={Database name}) will be different for your generated code. 名稱值為任意值。The name value is arbitrary.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "RazorPagesMovieContext": "Server=(localdb)\\mssqllocaldb;Database=RazorPagesMovieContext-bc;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

將應用程式部署到測試或生產環境伺服器時,可以使用環境變數來設定實際資料庫伺服器的連接字串。When the app is deployed to a test or production server, an environment variable can be used to set the connection string to a real database server. 如需詳細資訊,請參閱組態See Configuration for more information.

SQL Server Express LocalDBSQL Server Express LocalDB

LocalDB 為輕量版的 SQL Server Express 資料庫引擎,鎖定程式開發為其目標。LocalDB is a lightweight version of the SQL Server Express database engine that's targeted for program development. LocalDB 會依需求啟動,並以使用者模式執行,因此沒有複雜的組態。LocalDB starts on demand and runs in user mode, so there's no complex configuration. LocalDB 資料庫預設會在 C:\Users\<user>\ 目錄中建立 *.mdf 檔案。By default, LocalDB database creates *.mdf files in the C:\Users\<user>\ directory.

  • 從 [檢視]**** 功能表中,開啟 [SQL Server 物件總管]**** (SSOX)。From the View menu, open SQL Server Object Explorer (SSOX).

    檢視功能表

  • 以滑鼠右鍵按一下 Movie 資料表,並選取 [檢視表設計工具]****:Right click on the Movie table and select View Designer:

    在 Movie 資料表上開啟的操作功能表

    在設計工具中開啟的 Movie 資料表

請注意 ID 旁的索引鍵圖示。Note the key icon next to ID. 根據預設,EF 會為主索引鍵建立名為 ID 的屬性。By default, EF creates a property named ID for the primary key.

  • 以滑鼠右鍵按一下 Movie 資料表,並選取 [檢視資料]****:Right click on the Movie table and select View Data:

    開啟的電影資料表顯示資料表資料

植入資料庫Seed the database

使用下列程式碼,在 Models 資料夾中建立名為 SeedData 的新類別:Create a new class named SeedData in the Models folder with the following code:

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using RazorPagesMovie.Data;
using System;
using System.Linq;

namespace RazorPagesMovie.Models
{
    public static class SeedData
    {
        public static void Initialize(IServiceProvider serviceProvider)
        {
            using (var context = new RazorPagesMovieContext(
                serviceProvider.GetRequiredService<
                    DbContextOptions<RazorPagesMovieContext>>()))
            {
                // Look for any movies.
                if (context.Movie.Any())
                {
                    return;   // DB has been seeded
                }

                context.Movie.AddRange(
                    new Movie
                    {
                        Title = "When Harry Met Sally",
                        ReleaseDate = DateTime.Parse("1989-2-12"),
                        Genre = "Romantic Comedy",
                        Price = 7.99M
                    },

                    new Movie
                    {
                        Title = "Ghostbusters ",
                        ReleaseDate = DateTime.Parse("1984-3-13"),
                        Genre = "Comedy",
                        Price = 8.99M
                    },

                    new Movie
                    {
                        Title = "Ghostbusters 2",
                        ReleaseDate = DateTime.Parse("1986-2-23"),
                        Genre = "Comedy",
                        Price = 9.99M
                    },

                    new Movie
                    {
                        Title = "Rio Bravo",
                        ReleaseDate = DateTime.Parse("1959-4-15"),
                        Genre = "Western",
                        Price = 3.99M
                    }
                );
                context.SaveChanges();
            }
        }
    }
}

如果資料庫中有任何電影,則種子初始設定式會返回,而且不會新增任何電影。If there are any movies in the DB, the seed initializer returns and no movies are added.

if (context.Movie.Any())
{
    return;   // DB has been seeded.
}

新增種子初始設定式Add the seed initializer

Program.cs 中,修改 Main 方法來執行下列動作:In Program.cs, modify the Main method to do the following:

  • 從相依性插入容器中取得資料庫內容執行個體。Get a DB context instance from the dependency injection container.
  • 呼叫種子方法,並將其傳遞給內容。Call the seed method, passing to it the context.
  • 種子方法完成時處理內容。Dispose the context when the seed method completes.

下列程式碼顯示已更新的 Program.cs 檔案。The following code shows the updated Program.cs file.

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using RazorPagesMovie.Models;
using System;

namespace RazorPagesMovie
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();

            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;

                try
                {
                    SeedData.Initialize(services);
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred seeding the DB.");
                }
            }

            host.Run();

        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

當尚未執行時,會發生下列例外狀況 Update-DatabaseThe following exception occurs when Update-Database has not been run:

SqlException: Cannot open database "RazorPagesMovieContext-" requested by the login. The login failed. Login failed for user 'user name'.

測試應用程式Test the app

  • 刪除資料庫中的所有記錄。Delete all the records in the DB. 您可以使用瀏覽器或 SSOX 的刪除連結來執行這項操作You can do this with the delete links in the browser or from SSOX

  • 強制應用程式初始化 (呼叫 Startup 類別中的方法),以執行植入方法。Force the app to initialize (call the methods in the Startup class) so the seed method runs. 若要強制初始化,IIS Express 必須停止並重新啟動。To force initialization, IIS Express must be stopped and restarted. 您可以使用下列其中一個方法來執行此工作:You can do this with any of the following approaches:

    • 以滑鼠右鍵按一下通知區域中的 [IIS Express 系統匣] 圖示,然後按 [結束] 或 [ 停止網站]:Right click the IIS Express system tray icon in the notification area and tap Exit or Stop Site:

      IIS Express 系統匣圖示

      操作功能表

      • 如果您已在非偵錯模式中執行 VS,請按 F5 以偵錯模式執行。If you were running VS in non-debug mode, press F5 to run in debug mode.
      • 如果您已在偵錯模式中執行 VS,請停止偵錯工具,然後按 F5。If you were running VS in debug mode, stop the debugger and press F5.

接下來的教學課程將會改善資料的呈現。The next tutorial will improve the presentation of the data.

其他資源Additional resources

RazorPagesMovieContext 物件會處理連線到資料庫和將 Movie 物件對應至資料庫記錄的工作。The RazorPagesMovieContext object handles the task of connecting to the database and mapping Movie objects to database records. Startup.csConfigureServices 方法中,以相依性插入容器登錄資料庫內容:The database context is registered with the Dependency Injection container in the ConfigureServices method in Startup.cs:

// This method gets called by the runtime. 
// Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        // This lambda determines whether user consent for non-essential cookies is 
        // needed for a given request.
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    services.AddDbContext<RazorPagesMovieContext>(options =>
      options.UseSqlServer(
          Configuration.GetConnectionString("RazorPagesMovieContext")));
}

如需 ConfigureServices 中所用之方法的詳細資訊,請參閱:For more information on the methods used in ConfigureServices, see:

ASP.NET Core 組態系統會讀取 ConnectionStringThe ASP.NET Core Configuration system reads the ConnectionString. 對於本機開發,它會從檔案中的appsettings.js取得連接字串。For local development, it gets the connection string from the appsettings.json file.

您的產生程式碼會有不同的資料庫 (Database={Database name}) 名稱值。The name value for the database (Database={Database name}) will be different for your generated code. 名稱值為任意值。The name value is arbitrary.

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "RazorPagesMovieContext": "Server=(localdb)\\mssqllocaldb;Database=RazorPagesMovieContext-1234;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

將應用程式部署到測試或生產環境伺服器時,可以使用環境變數來設定實際資料庫伺服器的連接字串。When the app is deployed to a test or production server, an environment variable can be used to set the connection string to a real database server. 如需詳細資訊,請參閱組態See Configuration for more information.

SQL Server Express LocalDBSQL Server Express LocalDB

LocalDB 為輕量版的 SQL Server Express 資料庫引擎,鎖定程式開發為其目標。LocalDB is a lightweight version of the SQL Server Express database engine that's targeted for program development. LocalDB 會依需求啟動,並以使用者模式執行,因此沒有複雜的組態。LocalDB starts on demand and runs in user mode, so there's no complex configuration. LocalDB 資料庫預設會在 C:/Users/<user/> 目錄中建立 *.mdf 檔案。By default, LocalDB database creates *.mdf files in the C:/Users/<user/> directory.

  • 從 [檢視]**** 功能表中,開啟 [SQL Server 物件總管]**** (SSOX)。From the View menu, open SQL Server Object Explorer (SSOX).

    檢視功能表

  • 以滑鼠右鍵按一下 Movie 資料表,並選取 [檢視表設計工具]****:Right click on the Movie table and select View Designer:

    在電影資料表上開啟操作功能表

    在設計工具中開啟電影資料表

請注意 ID 旁的索引鍵圖示。Note the key icon next to ID. 根據預設,EF 會為主索引鍵建立名為 ID 的屬性。By default, EF creates a property named ID for the primary key.

  • 以滑鼠右鍵按一下 Movie 資料表,並選取 [檢視資料]****:Right click on the Movie table and select View Data:

    開啟的電影資料表顯示資料表資料

植入資料庫Seed the database

使用下列程式碼,在 Models 資料夾中建立名為 SeedData 的新類別:Create a new class named SeedData in the Models folder with the following code:

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;

namespace RazorPagesMovie.Models
{
    public static class SeedData
    {
        public static void Initialize(IServiceProvider serviceProvider)
        {
            using (var context = new RazorPagesMovieContext(
                serviceProvider.GetRequiredService<
                    DbContextOptions<RazorPagesMovieContext>>()))
            {
                // Look for any movies.
                if (context.Movie.Any())
                {
                    return;   // DB has been seeded
                }

                context.Movie.AddRange(
                    new Movie
                    {
                        Title = "When Harry Met Sally",
                        ReleaseDate = DateTime.Parse("1989-2-12"),
                        Genre = "Romantic Comedy",
                        Price = 7.99M
                    },

                    new Movie
                    {
                        Title = "Ghostbusters ",
                        ReleaseDate = DateTime.Parse("1984-3-13"),
                        Genre = "Comedy",
                        Price = 8.99M
                    },

                    new Movie
                    {
                        Title = "Ghostbusters 2",
                        ReleaseDate = DateTime.Parse("1986-2-23"),
                        Genre = "Comedy",
                        Price = 9.99M
                    },

                    new Movie
                    {
                        Title = "Rio Bravo",
                        ReleaseDate = DateTime.Parse("1959-4-15"),
                        Genre = "Western",
                        Price = 3.99M
                    }
                );
                context.SaveChanges();
            }
        }
    }
}

如果資料庫中有任何電影,則種子初始設定式會返回,而且不會新增任何電影。If there are any movies in the DB, the seed initializer returns and no movies are added.

if (context.Movie.Any())
{
    return;   // DB has been seeded.
}

新增種子初始設定式Add the seed initializer

Program.cs 中,修改 Main 方法來執行下列動作:In Program.cs, modify the Main method to do the following:

  • 從相依性插入容器中取得資料庫內容執行個體。Get a DB context instance from the dependency injection container.
  • 呼叫種子方法,並將其傳遞給內容。Call the seed method, passing to it the context.
  • 種子方法完成時處理內容。Dispose the context when the seed method completes.

下列程式碼顯示已更新的 Program.cs 檔案。The following code shows the updated Program.cs file.

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using RazorPagesMovie.Models;
using System;
using Microsoft.EntityFrameworkCore;

namespace RazorPagesMovie
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateWebHostBuilder(args).Build();

            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;

                try
                {
                    var context=services.
                        GetRequiredService<RazorPagesMovieContext>();
                    context.Database.Migrate();
                    SeedData.Initialize(services);
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred seeding the DB.");
                }
            }

            host.Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();
    }
}

生產環境應用程式不會呼叫 Database.MigrateA production app would not call Database.Migrate. 它會新增至前面的程式碼以免在尚未執行 Update-Database 時發生下列例外狀況:It's added to the preceding code to prevent the following exception when Update-Database has not been run:

SqlException:無法開啟登入要求的 "RazorPagesMovieContext-21" 資料庫。SqlException: Cannot open database "RazorPagesMovieContext-21" requested by the login. 登入失敗。The login failed. 使用者 'user name' 登入失敗。Login failed for user 'user name'.

測試應用程式Test the app

  • 刪除資料庫中的所有記錄。Delete all the records in the DB. 您可以使用瀏覽器或 SSOX 的刪除連結來執行這項操作You can do this with the delete links in the browser or from SSOX

  • 強制應用程式初始化 (呼叫 Startup 類別中的方法),以執行植入方法。Force the app to initialize (call the methods in the Startup class) so the seed method runs. 若要強制初始化,IIS Express 必須停止並重新啟動。To force initialization, IIS Express must be stopped and restarted. 您可以使用下列其中一個方法來執行此工作:You can do this with any of the following approaches:

    • 以滑鼠右鍵按一下通知區域中的 IIS Express 系統匣圖示,然後點選 [結束]**** 或 [停止站台]****:Right-click the IIS Express system tray icon in the notification area and tap Exit or Stop Site:

      IIS Express 系統匣圖示

      操作功能表

      • 如果您已在非偵錯模式中執行 VS,請按 F5 以偵錯模式執行。If you were running VS in non-debug mode, press F5 to run in debug mode.
      • 如果您已在偵錯模式中執行 VS,請停止偵錯工具,然後按 F5。If you were running VS in debug mode, stop the debugger and press F5.

應用程式會顯示植入的資料:The app shows the seeded data:

在 Chrome 中開啟的電影應用程式顯示電影資料

接下來的教學課程將會清除資料的呈現。The next tutorial will clean up the presentation of the data.

其他資源Additional resources