EF Core 在项目基本流程
- 实体类
- 数据库连接
- 实体映射
- service 数据操作
数据库连接
- startup 的ConfigureContainer方法中,注册一个自定义模块
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterModule(new PractiseForFreyaModule(Configuration, typeof(PractiseForFreyaModule).Assembly));
}
- 对应自定义模块类中,继承 Module 类,并注册数据容器
private void RegisterDbContext(ContainerBuilder builder)
{
builder.RegisterType<PractiseForFreyaDbContext>()
.AsSelf()
.As<DbContext>()
.WithParameter((pi, ctx) => pi.ParameterType == typeof(ConnectionString),
(pi, ctx) => ctx.Resolve<ConnectionString>())
.InstancePerLifetimeScope();
builder.RegisterType<EfRepository>().As<IRepository>().InstancePerLifetimeScope();
}
- 在 对应的 DbContext 类中,通过 OnConfiguring 配置和数据库的连接
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// 这里使用的是 mysql 数据库,也可以改用 UseSqlServer方法使用SqlServer 数据库
optionsBuilder.UseMySql(_connectionString.Value, new MySqlServerVersion(new Version(5, 7, 0)));
}
4.同时别忘记在项目的配置文件 appsettings.json
中,配置和数据库连接的字符串
"ConnectionStrings": {
"Default": "server=localhost;userid=root;password=123456;database=db_people;Allow User Variables=True;"
}
实体映射
在对应Dbcontext 类中,通过 OnModelCreating 方法,去配置 实体和数据库的映射
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
typeof(PractiseForFreyaDbContext).GetTypeInfo().Assembly.GetTypes()
.Where(t => typeof(IEntity).IsAssignableFrom(t) && t.IsClass).ToList().ForEach(
x =>
{
if (modelBuilder.Model.FindEntityType(x) == null)
modelBuilder.Model.AddEntityType(x);
});
}
InstancePerLifetimeScope
在 Autofac 中,InstancePerLifetimeScope 是用于注册组件的方法之一,它指定了组件的生命周期范围。
InstancePerLifetimeScope 表示每个生命周期范围(即一个 ILifetimeScope)将获得一个单独的实例。Autofac 中有不同的生命周期范围,最常见的是:
InstancePerDependency: 每次解析时都创建一个新的实例,它是默认的生命周期范围。每次调用 Resolve 或 Resolve<T> 时,都会得到一个新的实例。
InstancePerLifetimeScope: 每个 ILifetimeScope 一次解析获取一个实例。这意味着当在同一个 ILifetimeScope 下多次请求同一个组件时,它会返回相同的实例。但是,当你在不同的 ILifetimeScope 中请求时,它将返回不同的实例
Autofac 的ContainerBuilder 类
ContainerBuilder 是 Autofac 中用于构建依赖注入容器的重要类,它提供了一系列方法来注册、配置和构建容器。以下是一些常见的 ContainerBuilder 属性和方法:
常见的属性:
Properties: 这是一个字典属性,用于设置或获取容器的属性。可以用来存储和检索任意键值对的
配置信息。
常见的方法:
2. RegisterType
用于注册类型,将指定类型注册到容器中
builder.RegisterType<MyService>().As<IMyService>();
3. RegisterInstance
注册实例,将现有的实例注册到容器中
var myInstance = new MyClass();
builder.RegisterInstance(myInstance).As<IMyInterface>();
4. RegisterGeneric
用于注册泛型类型
builder.RegisterGeneric(typeof(MyGenericService<>)).As(typeof(IMyGenericService<>));
5. RegisterAssemblyTypes
注册程序集中的所有类型
builder.RegisterAssemblyTypes(typeof(MyAssembly).Assembly)
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces();
6. RegisterModule
注册 Autofac 模块
builder.RegisterModule(new MyAutofacModule());
7. Build
构建容器
var container = builder.Build();
这些是 ContainerBuilder 中常见的一些属性和方法,用于注册和配置依赖注入容器。通过这些方法,你可以灵活地注册各种类型、实例和配置信息到 Autofac 容器中
代码解读1
builder.RegisterType<PractiseForFreyaDbContext>()
.AsSelf()
.As<DbContext>()
.WithParameter((pi, ctx) => pi.ParameterType == typeof(ConnectionString),
(pi, ctx) => ctx.Resolve<ConnectionString>())
.InstancePerLifetimeScope();
builder.RegisterType<EfRepository>().As<IRepository>().InstancePerLifetimeScope();
这段代码是使用 Autofac 的 ContainerBuilder 来注册 PractiseForFreyaDbContext 类型的服务,并配置其生命周期以及参数的解析方式。
1. RegisterType<PractiseForFreyaDbContext>()
这一行代码表示要将 PractiseForFreyaDbContext 类型注册到容器中
2. AsSelf()
这表示将 PractiseForFreyaDbContext 类型本身视为服务。换句话说,它允许你使用 PractiseForFreyaDbContext 类型直接解析服务
3. As<DbContext>()
将 PractiseForFreyaDbContext 类型注册为 DbContext 类型的服务。这使得当需要解析 DbContext 类型的服务时,容器也能提供 PractiseForFreyaDbContext 类型的实例
4. WithParameter(...)
这是用于指定构造函数参数解析的部分。它告诉 Autofac 如何解析 PractiseForFreyaDbContext 构造函数中的 ConnectionString 参数
5. WithParameter((pi, ctx) => pi.ParameterType == typeof(ConnectionString), ...)
这段代码定义了一个谓词,检查构造函数的参数类型是否为 ConnectionString
6. (pi, ctx) => ctx.Resolve<ConnectionString>()
当满足条件时(参数类型是 ConnectionString),使用 Lambda 表达式指定参数的解析方式。在这里,它告诉容器通过 Resolve<ConnectionString>() 方法来解析 ConnectionString 类型的实例
7. InstancePerLifetimeScope()
这一行指定了注册服务的生命周期。InstancePerLifetimeScope() 表示每个生命周期范围内只会创建一个实例。一般情况下,它表示在每个 HTTP 请求范围内或者每次 LifetimeScope 被创建时都会创建一个新的实例
综合起来,这段代码的作用是注册 PractiseForFreyaDbContext 类型的服务,并且指定了构造函数中 ConnectionString 参数的解析方式为通过容器解析,同时定义了服务的生命周期为每个 LifetimeScope 创建一个实例
代码解读2
typeof(PractiseForFreyaDbContext).GetTypeInfo().Assembly.GetTypes()
.Where(t => typeof(IEntity).IsAssignableFrom(t) && t.IsClass).ToList().ForEach(
x =>
{
if (modelBuilder.Model.FindEntityType(x) == null)
modelBuilder.Model.AddEntityType(x);
});
这段代码用于获取程序集中实现了 IEntity 接口且为类(Class)的所有类型,并将这些类型动态地添加到 ModelBuilder 的数据库模型中,如果该类型尚未在模型中注册
1. typeof(PractiseForFreyaDbContext).GetTypeInfo().Assembly.GetTypes()
获取了 PractiseForFreyaDbContext 类所在程序集中的所有类型
2. Where(t => typeof(IEntity).IsAssignableFrom(t) && t.IsClass)
使用 LINQ 查询筛选出实现了 IEntity 接口并且是类(Class)的所有类型
3. ToList().ForEach(...)
对筛选出的类型列表进行迭代处理。
4. x => { ... }
Lambda 表达式,对于筛选出的每个类型执行以下操作
5. if (modelBuilder.Model.FindEntityType(x) == null)
检查当前类型在模型中是否已经存在。FindEntityType 方法用于在 ModelBuilder 的模型中查找指定的实体类型
6. modelBuilder.Model.AddEntityType(x)
如果模型中没有找到该类型的实体,则使用 AddEntityType 方法将该类型的实体动态添加到模型中
综合起来,这段代码的作用是遍历程序集中的所有类型,找到实现了 IEntity 接口并且是类的类型,然后将这些类型动态地添加到 ModelBuilder 的数据库模型中,以便 Entity Framework Core 在生成数据库迁移时能够将这些类型对应到数据库中的表结构