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 在生成数据库迁移时能够将这些类型对应到数据库中的表结构

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,427评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,551评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,747评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,939评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,955评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,737评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,448评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,352评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,834评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,992评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,133评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,815评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,477评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,022评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,147评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,398评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,077评论 2 355

推荐阅读更多精彩内容