4webapi创建EFCore框架的CodeFirst模式

使用工具:vs2019(基于.net5)

1. 将ef框架创建在类库里

①选择asp.net Core WebApi项目

image


②框架vs2019最高支持net5

image


③新建一个net5的类库并创建一个EFCore上下文对象类

image


④通过nutget包管理器安装如下两个包

一个是EFCore的,一个是用于将领域模型的实体映射到数据库中的。
image

注意,因为这个webapi项目是net5.0的,所以这两个包最好选低版本的安装,比如5.0,否则会不兼容
image


⑤在Models里设计好表

image

字段的限制可以在上下文对象里限制,这样逻辑比较清晰。

public class User
    {
        public int Id { get; set; }

        [Required, StringLength(maximumLength: 40), Column(TypeName = "varchar")]
        public string Email { get; set; }

        public string UserName { get; set; }
    }

⑥回到上下文对象里,进行配置

上下文对象必须基础DbContext类,重写里面的方法,

public class EfCoreDemoContext:DbContext
    {
        public EfCoreDemoContext()
        {

        }

        public EfCoreDemoContext(DbContextOptions options):base(options)
        {

        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            //设置连接字符串(也可以从配置项里读取)
            optionsBuilder.UseSqlServer("server=.;database=TestDb;uid=sa;pwd=123456");
        }

        //该方法是在设计字段时给字段添加限制,这样可以不用在领域模型的类里加上特性,这样更加直观看到每张表的字段的限制。
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            //设置User类的UserName属性的长度和不能为空
           modelBuilder.Entity<User>().Property(m => m.UserName).IsRequired().HasMaxLength(25).HasComment("用户名");

            base.OnModelCreating(modelBuilder);

        }

        //该属性名就是映射到数据库里的表名
       public DbSet<User> Users { get; set; }

    }

⑦在Models右键打开终端

image

全局安装ef工具
dotnet tool install --global dotnet-ef

首次使用数据库迁移,创建迁移日志
dotnet ef migrations add init

会创建一个快照文件夹,里面存迁移日志
image

添加一个迁移日志
dotnet ef migrations add change_1

image

然后即可进行迁移
dotnet ef database update

image


因为第一次是要进行数据库迁移创建数据库,所以,数据库连接字符串先写死。后续通过webapi项目访问该类库操作ef时,可以选择将连接字符串写在配置文件里。

首先创建一个静态类在类库里,方便类库读取webapi项目的配置文件

namespace Models
{
    public static class ConfigurationHelper
    {
        private static IConfiguration _config;
        public static void Configure(IConfiguration config)
        {
            _config = config;
        }

//根据配置文件键读取对应的值
        public static string GetConfigValueByKey(string key)
        {
            var value = _config.GetConnectionString(key);

            if (value == null)
            {
                return "";
            }
            return value;
        }
    }
}

然后修改山下文对象的配置重写的OnConfiguring方法

 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            //设置连接字符串(也可以从配置项里读取)
            optionsBuilder.UseSqlServer(ConfigurationHelper.GetConfigValueByKey("SchoolContext"));
        }

然后趣webapi项目的appsettings.json配置文件里添加数据库连接字符串配置

  "ConnectionStrings": {
    "SchoolContext": "Server=.;Database=TestDb;uid=sa;password=123456"
  }

创建好后webapi里添加Models项目的引用即可操作上下文对象了

在webapi项目的Startup.cs类的构造函数里注入类库里的静态类ConfigurationHelper需要的IConfiguration接口的具体对象

 public Startup(IConfiguration configuration)
        {
            Configuration = configuration;

            ConfigurationHelper.Configure(configuration);
        }

在webapi项目的Startup.cs类的ConfigureServices里进行构造函数注入,把eef上下文对象通过构造函数注入给控制器

services.AddScoped<EfCoreDemoContext>();

services.AddDbContext<EfCoreDemoContext>();

添加一个HomeController控制器,在该控制器里即可调用上下文对象操作数据库的数据了。

namespace WebApiDemo.Controllers
{
    [Route("/[controller]")]
    [ApiController]
    public class HomeController : ControllerBase
    {

        private EfCoreDemoContext _efCoreDemoContext;

        public HomeController(EfCoreDemoContext efCoreDemoContext)
        {
            _efCoreDemoContext = efCoreDemoContext;
        }

        [HttpGet]
        public void GetUser()
        {
          var user=  _efCoreDemoContext.Users.FirstOrDefault(m=>m.Email=="123");
        }


    }
}

运行调用该接口即可插入数据了



2. 上面是通过将webapi项目的IConfiguration接口的对象传给类库,然后类库进行调用读取webapi的项目文件的,比较麻烦,我们可以直接在webapi项目里配置好上下文对象的信息,然后将配置好的上下文对象传给类库的上下文对象里,这样就在webapi项目里读取配置文件信息了。

①删除上面创建的静态类ConfigurationHelper,并且在webapi的Startup类的构造函数也不需要进行注入了,删除即可。

②回到类库,在创建好的上下文对象里删除重写的OnConfiguring方法,因为连接字符串等配置信息直接在webapi项目里传一个配置好的上下文对象过来即可。

③修改EfCoreDemoContext上下文类的有参构造函数为:

也就是接收一个自身的配置上下文对象,这样在webapi项目里用构造函数注入过来即可
public EfCoreDemoContext(DbContextOptions<EfCoreDemoContext> options) : base(options){}

④去webapi项目的Startup类的ConfigureServices方法进行依赖注入

这里的上下文对象就是配置好连接字符串的上下文对象,然后类库的上下文对象用构造函数接收即可。

  services.AddDbContext<EfCoreDemoContext>(options=> {
                options.UseSqlServer(Configuration.GetConnectionString("SchoolContext"));
            });

⑤可以不在控制器里直接操作EF上下文,一般都是通过三层架构来,比如BLL,或者DAL

这里我们创建一个BLL类库,用来操作EF,在里面创建一个GetUser类

namespace BLL
{
    public class GetUser
    {
        private EfCoreDemoContext _efCoreDemoContext;

        public GetUser(EfCoreDemoContext efCoreDemoContext)
        {
            _efCoreDemoContext = efCoreDemoContext;
        }

        public string GetName()
        {
            var user = _efCoreDemoContext.Users.FirstOrDefault(m => m.Email == "123");

            return user.Email;
        }
    }
}

⑥webapi里还是要注入,否则类库里也得不到上下文对象

  services.AddDbContext<EfCoreDemoContext>(options=> {
                options.UseSqlServer(Configuration.GetConnectionString("SchoolContext"));
            });

⑦控制器里用这个类库的GetUser类即可。

注意,要通过依赖注入的方式注入GetUser类,否则构造函数里直接实例化是不行的,因为没有无参构造函数,就算有也不行,因为不通过依赖注入GetUser类,它里面的_efCoreDemoContext字段是没有值的。要通过容器给它里面的字段赋值。所以要通过构造函数注入来得到GetUser的对象。

namespace WebApiDemo.Controllers
{
    [Route("/[controller]")]
    [ApiController]
    public class HomeController : ControllerBase
    {

        private GetUser _useEF;

        public HomeController(GetUser useEF)
        {
            _useEF = useEF;
        }

        [HttpGet]
        public string GetUser()
        {
            return _useEF.GetName();
        }
    }
}

⑧依赖注入这个GetUser类的实例

services.AddScoped<GetUser>();

然后运行webapi的控制器即可。

如果第一次创建数据库时不用数据库迁移命令创建。可以直接运行api项目创建。步骤如下:

这样做可以第一次也不用将数据库连接字符串写死在上下文对象的OnConfiguring方法里。

在api项目里创建一个类

public static class DbInitializer
    {
        public static void Initialize(SchoolContext context)
        {
            var isscuess = context.Database.EnsureCreated();
        }
    }

修改api项目的program类(修改 Main 方法调用初始化数据库)

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

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

        private static void CreateDbIfNotExists(IHost host)
        {
            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;
                var context = services.GetRequiredService<EfCoreContext>();
                DbInitializer.Initialize(context);
            }
        }

    }

运行即可创建数据库。

posted @ 2022-05-04 10:22  青仙  阅读(380)  评论(0编辑  收藏  举报