在现代软件开发中,随着项目规模的扩大,数据库架构往往变得复杂。为了更好地管理和维护数据库,经常需要将数据库架构分割成多个部分,每个部分由不同的团队负责。Entity Framework Core(EF Core) 提供了一种灵活的方式来实现这一点。本文将介绍如何在.NET Core项目中使用EF Core来构建包含多个数据库上下文的项目结构。
首先,需要创建一个MVC Web API Core项目,这个项目将用于后续的数据库上下文操作。项目命名为MultipleDbContexts。创建项目后,需要引用一系列NuGet包。引用完成后,项目的MultipleDbContexts.csproj文件如下所示:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.Design" Version="2.0.0-preview1-final" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.3" />
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.2" />
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.2" />
</ItemGroup>
</Project>
接下来,需要创建一个新的数据库。可以使用免费的SQL Server Express或SQL Server for Developers。创建一个新的空数据库,并命名为multipleDbContexts。
为了使用数据库,需要在appsettings.json文件中添加连接字符串,如下所示:
{
"connectionString": "Server=host\\instance;Database=multipleDbContexts;Trusted_Connection=True;",
"Logging": {
// ...
}
}
接下来,需要创建两个数据库上下文项目:MultipleDbContexts.Users和MultipleDbContexts.Products。这两个项目将分别负责不同的数据库表。
MultipleDbContexts.Users项目将包含UsersDbContext,它将引用Users.User和Users.Role表。首先,需要添加一个新的类库到解决方案中,并在入口项目中引用它。MultipleDbContexts.Users类库需要引用EF的NuGet包,添加完所有需要的包后,MultipleDbContexts.Users.csproj文件如下所示:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.Design" Version="2.0.0-preview1-final" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.3" />
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.2" />
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.2" />
</ItemGroup>
</Project>
类似地,需要创建MultipleDbContexts.Products类库,并引用相同的NuGet包,然后从入口项目设置引用。
现在需要在MultipleDbContexts.Products和MultipleDbContexts.Users项目中添加表模型。
MultipleDbContexts.Products项目包含以下文件:
public class Products
{
public int Id { get; set; }
[MaxLength(60)]
public string Name { get; set; }
[MaxLength(600)]
public string ImageUrl { get; set; }
}
public class ProductsDbContext : DbContext
{
private readonly IConfiguration _config;
public ProductsDbContext(IConfiguration config, DbContextOptions<ProductsDbContext> options) : base(options)
{
_config = config ?? throw new System.ArgumentNullException(nameof(config));
}
public DbSet<Products> Products { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(_config["connectionString"], options =>
{
options.MigrationsHistoryTable("__UsersMigrationsHistory", "Products");
});
}
}
MultipleDbContexts.Users项目包含以下文件:
public class RoleModel
{
[Key, MaxLength(60)]
public string Key { get; set; }
[Required, MaxLength(250)]
public string Description { get; set; }
}
public class UserModel
{
[Key]
public int Id { get; set; }
[Required, MaxLength(50)]
public string Email { get; set; }
[StringLength(500)]
public string AboutUser { get; set; }
}
public class UsersDbContext : DbContext
{
private readonly IConfiguration _config;
public UsersDbContext(IConfiguration config, DbContextOptions<UsersDbContext> options) : base(options)
{
_config = config ?? throw new System.ArgumentNullException(nameof(config));
}
public DbSet<UserModel> Users { get; set; }
public DbSet<RoleModel> Roles { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(_config["connectionString"], options =>
{
options.MigrationsHistoryTable("__UsersMigrationsHistory", "Users");
});
}
}
现在需要在Startup.cs文件中将数据库上下文添加到依赖注入(DI)容器中:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<UsersDbContext>(options =>
{
options.UseSqlServer(Configuration["connectionString"],
sqlServerOptions =>
{
sqlServerOptions.MigrationsAssembly("MultipleDbContexts.Users");
});
});
services.AddDbContext<ProductsDbContext>(options =>
{
options.UseSqlServer(Configuration["connectionString"],
sqlServerOptions =>
{
sqlServerOptions.MigrationsAssembly("MultipleDbContexts.Products");
});
});
services.AddMvc();
}
为了使迁移工作,需要在使用dotnet ef命令时指定入口项目,这可以通过-s参数实现。还需要指定正在应用迁移的上下文,这可以通过--context参数实现。
dotnet ef migrations add products -s ../MultipleDbContexts/ --context ProductsDbContext
dotnet ef database update -s ../MultipleDbContexts/ --context ProductsDbContext
对于MultipleDbContexts.Users项目,也需要执行类似的命令。
dotnet ef migrations add users -s ../MultipleDbContexts/ --context UsersDbContext
dotnet ef database update -s ../MultipleDbContexts/ --context UsersDbContext
现在数据库应该已经有了表。让添加一些测试数据,执行以下SQL语句:
INSERT INTO [Users].[User] (AboutUser, Email) VALUES ('About user', 'me@example.com')
INSERT INTO [Users].[Role] ([Key], [Description]) VALUES ('Admin', 'Super Admin')
INSERT INTO Products.Product (ImageUrl, Name) VALUES ('/products/teapot.png', 'Teapot')
现在一切都应该就绪,编辑ValuesController以使用数据库上下文:
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
public object Get([FromServices] UsersDbContext usersDb, [FromServices] ProductsDbContext productsDb)
{
return new
{
usersDb.Users,
usersDb.Roles,
productsDb.Products
};
}
}
{
"users": [
{
"id": 1,
"email": "me@example.com",
"aboutUser": "About user"
}
],
"roles": [
{
"key": "Admin",
"description": "Super Admin"
}
],
"products": [
{
"id": 1,
"name": "Teapot",
"imageUrl": "/products/teapot.png"
}
]
}