.NET Core Web API中数据库相关配置

1.添加连接字符串在(appsettings.json)中

cs 复制代码
{
  //数据库连接信息
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=water;Trusted_Connection=True;TrustServerCertificate=True;"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

2.创建实体类

数据类型对应和导航属性设置

|---------------|------------|------------------------|
| SQL Server 类型 | EF Core 类型 | 示例字段 |
| bigint | long | Id 、 UserId 等 |
| varchar(n) | string | Name 、 Phone 等 |
| datetime | DateTime | CreateTime 、 OrderTime |
| decimal(p,s) | decimal | Price 、 Amount 等 |
| tinyint | byte | IsDefault 、 PayStatus |
| int | int | Status 、 Number 等 |

cs 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Water.Infrastructure.Data.Entities
{
    public class WaterInfo
    {
        public long Id { get; set; } // bigint
        public string Name { get; set; } // varchar(32)
        public long CategoryId { get; set; } // 外键
        public decimal Price { get; set; } // decimal(10,2)
        public string Image { get; set; } // varchar(255)
        public string Description { get; set; } // varchar(255)(可空)
        public int? Status { get; set; } // int(可空)
        public DateTime CreateTime { get; set; } // datetime
        public DateTime UpdateTime { get; set; } // datetime

        // 导航属性:关联Category、WaterSpec、OrderDetail、ShoppingCart
        public Category Category { get; set; }
        public ICollection<WaterSpec> WaterSpecs { get; set; }
        public ICollection<OrderDetail> OrderDetails { get; set; }
        public ICollection<ShoppingCart> ShoppingCarts { get; set; }
    }
}

3.配置数据库上下文

cs 复制代码
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Water.Infrastructure.Data.Entities;

namespace Water.Infrastructure.Data
{
    public class WaterDbContext:DbContext
    {
        public WaterDbContext(DbContextOptions<WaterDbContext> options) : base(options)
        { 
        }
        // 定义DbSet,对应数据库表
        public DbSet<AddressBook> AddressBooks { get; set; }
        public DbSet<Category> Categorys { get; set; }
        public DbSet<User> Users { get; set; }
        public DbSet<Order> Orders { get; set; }
        public DbSet<OrderDetail> OrderDetails { get; set; }
        public DbSet<ShoppingCart> ShoppingCarts { get; set; }
        public DbSet<WaterInfo> WaterInfos { get; set; }
        public DbSet<WaterSpec> WaterSpecs { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);//调用父类的默认配置逻辑,确保 EF Core 的默认约定(如主键自动识别)仍生效

            // 配置AddressBook表
            modelBuilder.Entity<AddressBook>(entity =>
            {
                entity.ToTable("AddressBook"); // 1. 指定映射到数据库的表名为"AddressBook"
                entity.HasKey(e => e.Id); // 2. 设值Id为主键
                entity.Property(e => e.Id).ValueGeneratedOnAdd(); // 3. 主键自增(插入时自动生成值)
                                                                  // 4. 配置字段约束:限制长度+非空
                entity.Property(e => e.Consignee).HasMaxLength(50).IsRequired(); // 收件人姓名:最长50字符,非空
                entity.Property(e => e.Phone).HasMaxLength(11).IsRequired(); // 电话:最长11字符(手机号),非空
                entity.Property(e => e.ProvinceName).HasMaxLength(32).IsRequired(); // 省份:最长32字符,非空
                entity.Property(e => e.CityName).HasMaxLength(32).IsRequired(); // 城市:同上
                entity.Property(e => e.DistrictName).HasMaxLength(32).IsRequired(); // 区县:同上
                entity.Property(e => e.Detail).HasMaxLength(200).IsRequired(); // 详细地址:最长200字符,非空

                // 5. 配置与User表的关联关系(外键+级联删除)
                entity.HasOne(d => d.User) // 每个AddressBook属于一个User(多对一)
                    .WithMany(p => p.AddressBooks) // 一个User可以有多个AddressBook(一对多)
                    .HasForeignKey(d => d.UserId) // 外键字段是AddressBook的UserId
                    .OnDelete(DeleteBehavior.Cascade); // 级联删除:当User被删除时,关联的AddressBook也自动删除
            });

            // 配置Category表
            modelBuilder.Entity<Category>(entity =>
            {
                entity.ToTable("Category");
                entity.HasKey(e => e.Id);
                entity.Property(e => e.Id).ValueGeneratedOnAdd();
                entity.Property(e => e.Name).HasMaxLength(32).IsRequired();
            });

            // 配置Order表
            modelBuilder.Entity<Order>(entity =>
            {
                entity.ToTable("Order");
                entity.HasKey(e => e.Id);
                entity.Property(e => e.Id).ValueGeneratedOnAdd();
                entity.Property(e => e.Number).HasMaxLength(50).IsRequired();
                entity.Property(e => e.Phone).HasMaxLength(11).IsRequired();
                entity.Property(e => e.Address).HasMaxLength(200).IsRequired();
                entity.Property(e => e.UserName).HasMaxLength(32).IsRequired();
                entity.Property(e => e.Consignee).HasMaxLength(32).IsRequired();

                entity.HasOne(d => d.User)
                    .WithMany(p => p.Orders)
                    .HasForeignKey(d => d.UserId)
                    .OnDelete(DeleteBehavior.Cascade);

                entity.HasOne(d => d.AddressBook)
                    .WithMany()
                    .HasForeignKey(d => d.AddressBookId)
                    .OnDelete(DeleteBehavior.Cascade);
            });

            // 配置OrderDetail表
            modelBuilder.Entity<OrderDetail>(entity =>
            {
                entity.ToTable("OrderDetail");
                entity.HasKey(e => e.Id);
                entity.Property(e => e.Id).ValueGeneratedOnAdd();
                entity.Property(e => e.Name).HasMaxLength(32).IsRequired();
                entity.Property(e => e.Image).HasMaxLength(255).IsRequired();

                entity.HasOne(d => d.Order)
                    .WithMany(p => p.OrderDetails)
                    .HasForeignKey(d => d.OrderId)
                    .OnDelete(DeleteBehavior.Cascade);

                entity.HasOne(d => d.WaterInfo)
                    .WithMany(p => p.OrderDetails)
                    .HasForeignKey(d => d.WaterInfoId)
                    .OnDelete(DeleteBehavior.Cascade);

                entity.HasOne(d => d.WaterSpec)
                    .WithMany(p => p.OrderDetails)
                    .HasForeignKey(d => d.WaterSpecId)
                    .OnDelete(DeleteBehavior.Cascade);
            });

            // 配置ShoppingCart表
            modelBuilder.Entity<ShoppingCart>(entity =>
            {
                entity.ToTable("ShoppingCart");
                entity.HasKey(e => e.Id);
                entity.Property(e => e.Id).ValueGeneratedOnAdd();
                entity.Property(e => e.Name).HasMaxLength(32).IsRequired();
                entity.Property(e => e.Image).HasMaxLength(255).IsRequired();

                entity.HasOne(d => d.User)
                    .WithMany(p => p.ShoppingCarts)
                    .HasForeignKey(d => d.UserId)
                    .OnDelete(DeleteBehavior.Cascade);

                entity.HasOne(d => d.WaterInfo)
                    .WithMany(p => p.ShoppingCarts)
                    .HasForeignKey(d => d.WaterInfoId)
                    .OnDelete(DeleteBehavior.Cascade);

                entity.HasOne(d => d.WaterSpec)
                    .WithMany(p => p.ShoppingCarts)
                    .HasForeignKey(d => d.WaterSpecId)
                    .OnDelete(DeleteBehavior.Cascade);
            });

            // 配置User表
            modelBuilder.Entity<User>(entity =>
            {
                entity.ToTable("User");
                entity.HasKey(e => e.Id);
                entity.Property(e => e.Id).ValueGeneratedOnAdd();
                entity.Property(e => e.OpenId).HasMaxLength(45).IsRequired();
                entity.Property(e => e.Name).HasMaxLength(32).IsRequired();
                entity.Property(e => e.Phone).HasMaxLength(11).IsRequired();
            });

            // 配置WaterInfo表
            modelBuilder.Entity<WaterInfo>(entity =>
            {
                entity.ToTable("WaterInfo");
                entity.HasKey(e => e.Id);
                entity.Property(e => e.Id).ValueGeneratedOnAdd();
                entity.Property(e => e.Name).HasMaxLength(32).IsRequired();
                entity.Property(e => e.Image).HasMaxLength(255).IsRequired();

                entity.HasOne(d => d.Category)
                    .WithMany(p => p.WaterInfos)
                    .HasForeignKey(d => d.CategoryId)
                    .OnDelete(DeleteBehavior.Cascade);
            });

            // 配置WaterSpec表
            modelBuilder.Entity<WaterSpec>(entity =>
            {
                entity.ToTable("WaterSpec");
                entity.HasKey(e => e.Id);
                entity.Property(e => e.Id).ValueGeneratedOnAdd();
                entity.Property(e => e.SpecName).HasMaxLength(32).IsRequired();

                entity.HasOne(d => d.WaterInfo)
                    .WithMany(p => p.WaterSpecs)
                    .HasForeignKey(d => d.WaterId)
                    .OnDelete(DeleteBehavior.Cascade);
            });
        }
    }
}

3.1.Fluent API配置

1. 哪些情况可以依赖默认约定(不用显式配置)?

EF Core 的 "约定优于配置" 原则会自动处理一些基础映射,比如:

  • 主键:实体中名为Id或 "类名 + Id" 的属性(如AddressBookId)会被自动识别为主键,且默认是自增的(ValueGeneratedOnAdd)。
  • 表名:默认用实体类名的复数形式(如AddressBook实体→AddressBooks表)。
  • 外键:如果实体有导航属性(如AddressBook中的User User),且存在UserId属性,EF 会自动推断UserId是关联User表的外键。
  • 数据类型:基础类型(如string→nvarchar(max)、int→int、decimal→decimal(18,2))会自动映射,无需额外配置。

2. 哪些情况必须 / 建议显式配置?

当默认约定不符合需求时,必须显式配置(用 Fluent API 或特性):

(1)主键非默认命名如果主键不叫

Id或 "类名 + Id",比如AddressBook的主键是BookId,则必须显式配置主键:

cs 复制代码
modelBuilder.Entity<AddressBook>().HasKey(e => e.BookId);
(2)表名 / 列名自定义如果表名不想用复数

(如AddressBook实体对应表AddressBook而非AddressBooks),或列名与属性名不同(如属性Consignee对应列Receiver):

cs 复制代码
// 表名
modelBuilder.Entity<AddressBook>().ToTable("AddressBook"); 
// 列名
modelBuilder.Entity<AddressBook>().Property(e => e.Consignee).HasColumnName("Receiver");
(3)字段长度 / 约束

string类型默认映射为nvarchar(max),但实际业务中通常需要限制长度(如varchar(50)),否则可能导致数据库性能问题或存储空间浪费:

cs 复制代码
// 限制长度为50,且非空
modelBuilder.Entity<AddressBook>().Property(e => e.Consignee).HasMaxLength(50).IsRequired();
(4)外键关系复杂比如多对多关系、自引用关系,或外键命名不符合默认约定

(如AddressBook中关联User的外键是UId而非UserId):

cs 复制代码
// 显式指定外键
modelBuilder.Entity<AddressBook>()
    .HasOne(d => d.User)
    .WithMany(p => p.AddressBooks)
    .HasForeignKey(d => d.UId); // 外键是UId而非默认的UserId
(5)数据类型精确控制默认映射可能不符合数据库设计

(如decimal默认是decimal(18,2),但业务需要decimal(10,2);string需要映射为varchar而非默认的nvarchar):

cs 复制代码
// 精确指定decimal精度
modelBuilder.Entity<Order>().Property(e => e.Amount).HasPrecision(10, 2);
// 映射为varchar(默认是nvarchar)
modelBuilder.Entity<User>().Property(e => e.Phone).IsUnicode(false); // IsUnicode(false)对应varchar
(6)索引、默认值、检查约束等高级配置如果需要给字段加索引

(如User表的Phone字段需要唯一索引),或设置默认值(如CreateTime默认是当前时间):

cs 复制代码
// 唯一索引
modelBuilder.Entity<User>().HasIndex(e => e.Phone).IsUnique();
// 默认值
modelBuilder.Entity<User>().Property(e => e.CreateTime).HasDefaultValueSql("GETDATE()");

4.在program.cs中注册数据库上下文

cs 复制代码
var builder = WebApplication.CreateBuilder(args);

//注册ef core上下文,关联sql server连接字符串
builder.Services.AddDbContext<WaterDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
相关推荐
自不量力的A同学28 分钟前
Redisson 4.2.0 发布,官方推荐的 Redis 客户端
数据库·redis·缓存
Exquisite.30 分钟前
Mysql
数据库·mysql
全栈前端老曹1 小时前
【MongoDB】深入研究副本集与高可用性——Replica Set 架构、故障转移、读写分离
前端·javascript·数据库·mongodb·架构·nosql·副本集
R1nG8631 小时前
CANN资源泄漏检测工具源码深度解读 实战设备内存泄漏排查
数据库·算法·cann
阿钱真强道1 小时前
12 JetLinks MQTT直连设备事件上报实战(继电器场景)
linux·服务器·网络·数据库·网络协议
逍遥德2 小时前
Sring事务详解之02.如何使用编程式事务?
java·服务器·数据库·后端·sql·spring
笨蛋不要掉眼泪2 小时前
Redis哨兵机制全解析:原理、配置与实战故障转移演示
java·数据库·redis·缓存·bootstrap
Coder_Boy_2 小时前
基于SpringAI的在线考试系统-整体架构优化设计方案
java·数据库·人工智能·spring boot·架构·ddd
.房东的猫10 小时前
ERP(金蝶云星空)开发【安装篇】
c#
fen_fen10 小时前
Oracle建表语句示例
数据库·oracle