EF Core 的项目流程

EF Core 在项目基本流程

  1. 实体类
  2. 数据库连接
  3. 实体映射
  4. service 数据操作

数据库连接

  1. startup 的ConfigureContainer方法中,注册一个自定义模块
 public void ConfigureContainer(ContainerBuilder builder)
    {
        builder.RegisterModule(new PractiseForFreyaModule(Configuration, typeof(PractiseForFreyaModule).Assembly));
    }
  1. 对应自定义模块类中,继承 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();
    }
  1. 在 对应的 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 在生成数据库迁移时能够将这些类型对应到数据库中的表结构

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容