ASP.NET Core EFCore之DB First

一、引入EFCore相关组件

创建一个Web API项目,使用NuGet引入如下四个组

Microsoft.EntityFrameworkCore

Microsoft.EntityFrameworkCore.SqlServer

Microsoft.EntityFrameworkCore.Design

Microsoft.EntityFrameworkCore.Tools

二、生成实体类和数据库上下文

EFCore中,使用DB First模式生成实体类和数据库上下文时需要使用Scaffold-DbContext命令,该命令的格式如下所示:

复制代码
Scaffold-DbContext [-Connection] <String> [-Provider] <String> [-OutputDir <String>] [-ContextDir <String>] [-Context <String>] [-Schemas <String[]>] [-Tables <String[]>] [-DataAnnotations] [-UseDatabaseNames] [-Force] [-Project <String>] [-StartupProject <String>][<CommonParameters>]

Scaffold-DbContext命令中的参数说明如下表所示:

|------------------|------------------------------------------------------|
| 名称 | 含义 |
| -Connection | 指定数据库的连接字符串 |
| -Provider | 指定要使用的提供程序。例如Microsoft.EntityFrameworkCore.SqlServer |
| -OutputDir | 指定用于输出类的目录。如果省略,则使用顶级项目目录 |
| -ContextDir | 指定存放DbContext的目录 |
| -Context | 指定生成的DbContext类的名称 |
| -Schemas | 指定要为其生成类的模式 |
| -Tables | 指定要为其生成类的表 |
| -DataAnnotations | 使用DataAnnotation属性在可能的情况下配置模型 |
| -Force | 强制脚手架覆盖现有文件 |
| -Project | 指定实体类和数据库上下文存放在的项目名称 |
| -StartupProject | 指定启动项目名称 |

打开NuGet控制台,输入如下命令

复制代码
Scaffold-DbContext -Connection "database=ST_admin;Persist Security Info=true;password=123;User ID =sa;server =DESKTOP-RSH1EVH\SQL2012;TrustServerCertificate=True" -Provider Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -ContextDir DbContext -Context SqlContexttemp -Force

可以发现已经创建了实体类CountryProvince和数据库上下文类SqlContext。到此为止,我们已经可以通过Scaffold-DbContext命令生成实体类和数据库上下文了。

对实体类和数据库上下文进行更新了,我们只需要在Scaffold-DbContext命令后面加上-Force参数即可,它可以帮助我们重新生成实体类和数据库上下文并覆盖原有文件

三、分层项目中如何在其他类库中生成实体类和数据库上下文?

在实际开发过程中,很多项目都会进行分层操作,例如新建一个Demo.Models类库用来存放实体类和数据库上下文

首先在Demo.Models中使用NuGet引入EFCore的相关组件

Microsoft.EntityFrameworkCore

Microsoft.EntityFrameworkCore.SqlServer

Microsoft.EntityFrameworkCore.Design

Microsoft.EntityFrameworkCore.Tools

最后在Scaffold-DbContext命令中设置-Project-StartupProject参数,代码如下:

cs 复制代码
Scaffold-DbContext -Connection "database=ST_admin;Persist Security Info=true;password=123;User ID =sa;server =DESKTOP-RSH1EVH\SQL2012;TrustServerCertificate=True" -Provider Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -ContextDir DbContext -Context SqlContexttemp -Force -Project Demo.Models -StartupProject Demo.Models

四、在Startup.cs文件中添加数据库上下文,代码如下所示:

cs 复制代码
using Canteen.Services;
using EFDemo;
using Microsoft.EntityFrameworkCore;
using NPOI.OpenXmlFormats.Dml;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();
Canteen.Services.ConfigurationHelper.Configure(builder.Configuration);

// 添加其他配置文件
var configurationBuilder = new ConfigurationBuilder();
Gobal_Setting.Instance.AddConfs().ForEach(x => configurationBuilder.AddJsonFile(x, optional: true, reloadOnChange: true));
var configuration = configurationBuilder.Build();
builder.Configuration.AddConfiguration(configuration);// 替换默认配置  

//string tempv = Gobal_Setting.Instance.GetSettingValue("name");
//string id = Gobal_Setting.Instance.GetSettingValue("id");
//string school = Gobal_Setting.Instance.GetSettingValue("school");

// 配置数据库上下文
builder.Services.AddDbContext<SqlServerContext>(options =>
{
    var sqlServerConString = ConfigurationHelper.GetConfigValueByKey("ConnectionStrings:MSSQLDbConnection");// Gobal_Setting.Instance.GetSettingValue("ConnectionStrings:MSSQLDbConnection");
    options.UseSqlServer(sqlServerConString);
});

builder.Services.AddCors(policy =>
{
    policy.AddPolicy("AnyPolicy", opt => opt
            //.WithOrigins(Gobal_Setting.Instance.GetSettingValue("urls_ui").Split(','))
            .AllowAnyOrigin()
            .AllowAnyMethod()
            //.AllowCredentials()
            .AllowAnyHeader());
});

builder.Services.AddScoped<IDatabaseContext, SqlServerContext>();
builder.Services.AddSwaggerGen(options =>
{
    //http://localhost:38041/swagger/index.html
    options.SwaggerDoc("v1", new OpenApiInfo
    {
        Version = "v1",
        Title = "API标题",
        Description = "API描述"
    });
    var xmlFile = AppContext.BaseDirectory;
  
});

var app = builder.Build();

app.UseSwagger();
app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "测试");
    c.DocumentTitle = "API";
    //http://localhost:38041/swagger/index.html
});

app.UseCors("AnyPolicy");
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

ConfigurationHelper代码如下:

cs 复制代码
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Text;

namespace Canteen.Services
{
    public class ConfigurationHelper
    {
        public static void Configure(IConfiguration config)
        {
            _configuration = config;
        }

        public static IConfiguration _configuration;

        public static string GetConfigValueByKey(string key)
        {
            return _configuration[key];
        }

    }
}

Gobal_Setting 代码如下:

cs 复制代码
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Concurrent;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Configuration;

namespace EFDemo
{
    public class Gobal_Setting
    {
        private static Gobal_Setting _obj = null;

        public static Gobal_Setting Instance
        {
            get
            {
                if (_obj == null)
                    _obj = new Gobal_Setting();
                return _obj;
            }
        } 

        private readonly List<string> ConfileList = new List<string>();

        private readonly ConcurrentDictionary<string, object> _settingDictionary = new ConcurrentDictionary<string, object>();

        #region 递归获取文件树
        private List<string> GetPathList(string path = "")
        {
            List<string> pathList = new List<string>();

            try
            {
                DirectoryInfo folder = new DirectoryInfo(path);

                if (folder.Exists)
                {
                    foreach (FileInfo file in folder.GetFiles().OrderByDescending(fi => fi.Name))//根据名称排线,最后的覆盖
                    {
                        pathList.Add(file.FullName);
                    }

                    foreach (DirectoryInfo dir in folder.GetDirectories().OrderByDescending(fdir => fdir.Name))
                    {
                        pathList.AddRange(GetPathList(dir.FullName));
                    }
                }
            }
            catch (Exception ex) { Console.WriteLine(ex.Message); }

            return pathList;
        }
        #endregion
         
        /// <summary>
        /// 添加配置文件夹
        /// </summary>
        public List<string> AddConfs(string ConfDirectory = "conf")
        {
            string ConfPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfDirectory);
            List<string> jsonfiles = GetPathList(ConfPath);
            jsonfiles.ForEach(x => AddJsonFile(x));  
            return ConfileList;
        }

        public void AddJsonFile(string ConfigFullFilePath)
        {
            try
            {
                if (!ConfigFullFilePath.Contains("/") && !ConfigFullFilePath.Contains("\\"))
                    ConfigFullFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigFullFilePath);

                string Config_json = ReadConfig(ConfigFullFilePath);
                if (string.IsNullOrEmpty(Config_json))
                    return;

                var kv = JsonConvert.DeserializeObject<Dictionary<string, object>>(Config_json);
                foreach (KeyValuePair<string, object> item in kv)
                {
                    if (!_settingDictionary.Keys.Contains(item.Key))
                        _settingDictionary.TryAdd(item.Key, item.Value);
                    else
                        _settingDictionary[item.Key] = item.Value;
                }

                if (!ConfileList.Contains(ConfigFullFilePath))
                    ConfileList.Add(ConfigFullFilePath);

                //AddSettings(JsonConvert.DeserializeObject<Dictionary<string, object>>(Config_json));
            }
            catch (Exception ex) { Console.WriteLine("AddJsonFile Error :" + ex.Message); }
        }

        public int GetCount()
        {
            return _settingDictionary.Count;
        }
        public List<KeyValuePair<string, object>> GetItems()
        {
            return _settingDictionary.ToArray().ToList();
        }

        public int AddSettings(Dictionary<string, object> dictionary)
        {
            if (dictionary != null && dictionary.Count > 0)
            {
                foreach (var item in dictionary)
                {
                    _settingDictionary[item.Key] = item.Value;
                }
            }
            return _settingDictionary.Count;
        }
 
        public string GetSettingValue(string settingKey)
        {
            try
            {
                if (settingKey.Contains(":"))
                {
                    string[] ary = settingKey.Split(':');
                    _settingDictionary.TryGetValue(ary[0], out object? v0);

                    JToken retDataJson = JToken.Parse(v0?.ToString());
                    return retDataJson?.SelectToken(ary[1])?.ToString();

                    //JArray jArray = v.result;
                    //foreach (JToken jt in jArray)
                    //{
                    //    dynamic v1 = JsonConvert.DeserializeObject(jt.ToString().Replace("/r/n", ""));
                    //    string v1_uuid = v1.uuid;
                    //    string v1_name = v1.name;  
                    //} 
                }
                else
                {
                    _settingDictionary.TryGetValue(settingKey, out object val);
                    return val?.ToString();
                }
            }
            catch { return ""; }
        }

        public int GetSettingValue_Int(string settingKey)
        {
            var value = GetSettingValue(settingKey);
            int ret;
            int.TryParse(value?.ToString(), out ret);
            return ret;
        }

        public string SetSettingValue(string settingKey, string settingValue)
        {
            _settingDictionary[settingKey] = settingValue;
            return settingValue;
        }

        public int SetSettingValue_Int(string settingKey, int settingValue)
        {
            _settingDictionary[settingKey] = settingValue;
            return settingValue;
        }

        //public ConcurrentDictionary<string, object> GetSetting()
        //{
        //    return _settingDictionary;
        //}

        #region 读配置文件
        /// <summary>
        /// 读取配置文件
        /// </summary>
        /// <param name="ConfigFullFilePath"></param>
        /// <returns></returns>
        private string ReadConfig(string ConfigFullFilePath)
        {
            try
            {
                if (!System.IO.File.Exists(ConfigFullFilePath))
                    return "";

                //单行双斜杆注释正则表达式
                Regex reg = new Regex("^[^\"]*((((?<=@)\"[^\"]*\")|((?<!@)\"(\\\\\\\\|\\\\\"|[^\"])*\"))[^\"]*)*//");

                StringBuilder Context = new StringBuilder();
                string[] Lines = File.ReadAllLines(ConfigFullFilePath);
                foreach (string line in Lines)
                {
                    bool hasComment = reg.IsMatch(line);
                    if (hasComment)
                    {
                        string v = reg.Match(line).Value.Trim();
                        int x = v.LastIndexOf("//");
                        if (x > 0)
                            Context.Append(v.Substring(0, x));
                    }
                    else
                        Context.Append(line);
                }

                return Context.ToString();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return "";
            }
            finally
            {

            }
        }
        #endregion

        #region 写配置文件
        /// <summary>
        /// 写配置文件
        /// </summary>
        /// <param name="Key"></param>
        /// <param name="oValue"></param>
        public bool WriteConfig(string Key, object oValue)
        {
            try
            {
                if (oValue.GetType() != typeof(string) && oValue.GetType() != typeof(int))
                    return false;

                foreach (var ConfigFullFilePath in ConfileList)
                {
                    if (!File.Exists(ConfigFullFilePath))
                        continue;

                    var config_w = new ConfigurationBuilder()
                      .AddJsonFile(ConfigFullFilePath)
                      .Build();

                    if (config_w[Key] != null)
                    {
                        StringBuilder Context = new StringBuilder();
                        string[] Lines = File.ReadAllLines(ConfigFullFilePath);
                        string[] KeySectionArray = Key.Split(':');

                        int StartLine = 0;
                        string SerachKey = Key;
                        if (KeySectionArray.Length > 1)
                            SerachKey = KeySectionArray[0];

                        for (int i = 0; i < Lines.Length; i++)
                        {
                            string line = Lines[i];

                            if (StartLine == 0 && KeySectionArray.Length > 1)
                            {
                                if (line.Contains("\"" + SerachKey + "\""))
                                {
                                    StartLine = i;
                                    SerachKey = KeySectionArray[1];
                                }
                                else
                                    continue;
                            }

                            if (line.Contains("\"" + SerachKey + "\""))
                            {
                                //TODO:替换时候,判断字符串还是数字,字符串需要匹配引号才更正确
                                Lines[i] = line.Replace(config_w[Key], oValue.ToString());
                                break;
                            }
                        }


                        Console.WriteLine("WriteConfig:" + ConfigFullFilePath);
                        File.WriteAllLines(ConfigFullFilePath, Lines);
                        return true;
                    }
                }

                return false;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return false;
            }
        }
 

        public object SetSettingValue(string settingKey, object settingValue)
        {
            throw new NotImplementedException();
        }

        public int AddSettings(KeyValuePair<string, object> kv)
        {
            throw new NotImplementedException();
        }

        public int AddSettings(string key, object value)
        {
            throw new NotImplementedException();
        }
        #endregion

    } 
}

五、新增控制器

参考:https://blog.csdn.net/HerryDong/article/details/128091994?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0-128091994-blog-125111977.235^v43^control&spm=1001.2101.3001.4242.1&utm_relevant_index=3

相关推荐
SeaTunnel4 小时前
Apache SeaTunnel MySQL CDC 支持按时间启动吗?
大数据·数据库·mysql·开源·apache·seatunnel
韩立学长4 小时前
Springboot喵趣网上宠物店的设计和实现5pidz60b(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·后端
想起你的日子4 小时前
EFCore之Code First
前端·.netcore
深耕AI4 小时前
【wordpress系列教程】07 网站迁移与备份
运维·服务器·前端·数据库
刘大猫.5 小时前
XNMS项目-mysql数据库同步
数据库·统计·同步·数据同步·数据统计·数据库同步·业务统计
踢足球09295 小时前
寒假打卡:2026-01-22
数据库·sql
数巨小码人5 小时前
核心架构深度解析-揭开国产数据库内核的神秘面纱
数据库·架构
薛晓刚5 小时前
MySQL 精度扩展时候的DDL阻塞对比Oracle
数据库
卓怡学长5 小时前
m119在线购书商城系统
java·数据库·spring boot·spring·汽车