.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")));
相关推荐
q***06479 小时前
MySQL的UPDATE(更新数据)详解
数据库·mysql
8***B9 小时前
MySQL性能
数据库·mysql
q***72199 小时前
oracle使用PLSQL导出表数据
数据库·oracle
数据库生产实战9 小时前
Oracle DG备库日志切换解析,Private strand flush not complete如何理解?(基础知识)
数据库·oracle
百***75749 小时前
从 SQL 语句到数据库操作
数据库·sql·oracle
i***39589 小时前
SQL 注入详解:原理、危害与防范措施
数据库·sql·oracle
m***567211 小时前
Win10下安装 Redis
数据库·redis·缓存
Warren9811 小时前
Python自动化测试全栈面试
服务器·网络·数据库·mysql·ubuntu·面试·职场和发展
Eiceblue11 小时前
通过 C# 将 HTML 转换为 RTF 富文本格式
开发语言·c#·html
IUGEI11 小时前
synchronized的工作机制是怎样的?深入解析synchronized底层原理
java·开发语言·后端·c#