.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")));
相关推荐
大G的笔记本2 小时前
高频 Redis 面试题答案解析
数据库·redis·缓存
周杰伦fans3 小时前
C# 中 Entity Framework (EF) 和 EF Core 里的 `AsNoTracking` 方法
开发语言·c#
万事大吉CC3 小时前
SQL语法基础教程
数据库·oracle
她说彩礼65万3 小时前
C#设计模式 单例模式实现方式
单例模式·设计模式·c#
betazhou3 小时前
Oracle dgbroker常规命令管理简介
数据库·oracle·adg·dbbroker
海边夕阳20064 小时前
PostgreSQL性能调优:解决表膨胀、索引碎片和无效索引问题
数据库·经验分享·postgresql·性能优化
一 乐4 小时前
个人理财系统|基于java+小程序+APP的个人理财系统设计与实现(源码+数据库+文档)
java·前端·数据库·vue.js·后端·小程序
m0_748248024 小时前
Redis的数据淘汰策略解读
数据库·redis·缓存
哥哥还在IT中5 小时前
让数据库更智能-大模型如何优化我们的SQL查询
数据库·sql