ABP.NET 创建项目(二)(进阶部分)
不再以Task类说明
7.表设计
类需求:
Student.cs
:"学生"的基础字段类(主键Id
,为基类所自动生成)
StudentExtra.cs
:"学生"的额外字段类(一对一,与Student.cs
连接键StudentId
)
StudnetConst.cs
:存储所有有关"学生"字段的最大数据长度
ClassGroup.cs
:"班级"/"小组"的基础字段(主键Id
,为基类所自动生成)
StudentClassGroup.cs
:"班级"/"小组"的完全字段(有连接键StudentId
,ClassGroupId
)
ClassGroupConst.cs
:存储所有有关"班级"/"小组"字段的最大数据长度
ClassGroupType.cs
:枚举类,由于把"班级"与"小组"概念混成一体,因此需要字段说明
using Abp.Domain.Entities.Auditing;
using System.Collections.Generic;
using System.Linq;
namespace Practice2023.Students
{
/// <summary>
/// 学生信息
/// </summary>
public class Student : FullAuditedEntity<long>
{
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 性别
/// </summary>
public string Sex { get; set; }
/// <summary>
/// 身份证号码
/// </summary>
public string IdCardNumber { get; set; }
/// <summary>
/// 学号
/// </summary>
public string Number { get; set; }
/// <summary>
/// 额外信息
/// </summary>
public virtual StudentExtra Extra { get; set; }
/// <summary>
/// 所在班组
/// </summary>
public virtual ICollection<StudentClassGroup> ClassGroups { get; set; } = new List<StudentClassGroup>();
public Student()
{
}
public Student(string name, string sex = null, string idCardNumber = null, string number = null)
{
this.Name = name;
this.Sex = sex;
this.IdCardNumber = idCardNumber;
this.Number = number;
}
public void AddExtra(string extra1 = null, string extra2 = null, string extra3 = null)
{
this.Extra = new StudentExtra(this.Id, extra1, extra2, extra3);
}
public void AddToClassGroup(long classGroupId)
{
var classGroup = this.ClassGroups.FirstOrDefault(x => x.ClassGroupId == classGroupId);
if (classGroup != null) return;
this.ClassGroups.Add(new StudentClassGroup(this.Id, classGroupId));
}
//移除出组
public void RemoveToClassGroup(long classGroupId)
{
var classGroup = this.ClassGroups.FirstOrDefault(x => x.ClassGroupId == classGroupId);
if (classGroup == null) return;
this.ClassGroups = this.ClassGroups.Where(x => x.ClassGroupId != classGroupId).ToList();
}
}
}
这里看到ClassGroup
是ICollection<StudentClassGroup>
。因此1个学生可以参加多个班级/小组
using Abp.Domain.Entities.Auditing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Practice2023.Students
{
public class StudentExtra : FullAuditedEntity<long>
{
public long StudentId { get; set; }
public virtual Student Student { get; set; }
public string Extra1 { get; set; }
public string Extra2 { get; set; }
public string Extra3 { get; set; }
public StudentExtra()
{
}
public StudentExtra(long studentId, string extra1 = null, string extra2 = null, string extra3 = null)
{
this.StudentId = studentId;
this.Extra1 = extra1;
this.Extra2 = extra2;
this.Extra3 = extra3;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Practice2023.Students
{
public class StudentConsts
{
public const int MaxNameLength = 32;
public const int MaxSexLength = 8;
public const int MaxIdCardNumberLength = 32;
public const int MaxNumberLength = 32;
public const int MaxExtra1Length = 64;
public const int MaxExtra2Length = 64;
public const int MaxExtra3Length = 64;
}
}
using Abp.Domain.Entities.Auditing;
using Practice2023.ClassGroups;
using System;
namespace Practice2023.Students
{
//我可以理解为ClassGroupExtra?
public class StudentClassGroup : CreationAuditedEntity<long>, IDeletionAudited
{
//小组/班级创始人?
public long StudentId { get; set; }
public virtual Student Student { get; set; }
//小组/班级的主键
public long ClassGroupId { get; set; }
public virtual ClassGroup ClassGroup { get; set; }
public DateTime? DeletionTime { get; set; }
public bool IsDeleted { get; set; }
public long? DeleterUserId { get; set; }
public StudentClassGroup(long studentId, long classGroupId)
{
this.StudentId = studentId;
this.ClassGroupId = classGroupId;
}
}
}
using Abp.Domain.Entities.Auditing;
namespace Practice2023.ClassGroups
{
/// <summary>
/// 班组
/// </summary>
public class ClassGroup : FullAuditedEntity<long>
{
/// <summary>
/// 班组名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 班组类型
/// </summary>
public ClassGroupType Type { get; set; }
public ClassGroup(string name, ClassGroupType type)
{
this.Name = name;
this.Type = type;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Practice2023.ClassGroups
{
public class ClassGroupConsts
{
public const int MaxNameLength = 128;
}
}
using System.ComponentModel;
namespace Practice2023.ClassGroups
{
public enum ClassGroupType
{
/// <summary>
/// 班级
/// </summary>
[Description("班级")] Class = 1,
/// <summary>
/// 小组
/// </summary>
[Description("小组")] Group = 2
}
}
这里注意为了使用 GetDescription()
方法,你需要在程序中引入 System.ComponentModel
命名空间,以便使用 DescriptionAttribute 类。可用于获取上面的"班级"或"小组"Description
8:服务端
一:IClassGroupAppService.cs
,ClassGroupAppService
:关于班级/小组类的数接口
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Practice2023.ClassGroups.Dto;
using System.Threading.Tasks;
namespace Practice2023.ClassGroups
{
public interface IClassGroupAppService : IApplicationService
{
Task<ClassGroupDto> GetAsync(long id);
Task<PagedResultDto<ClassGroupDto>> GetPagedListAsync(PagedClassGroupResultRequestDto input);
Task CreateAsync(CreateClassGroupDto input);
Task UpdateAsync(UpdateClassGroupDto input);
Task DeleteAsync(long id);
}
}
接口定义了查询(GetAsync
),分页列表(GetPagedListAsync
),创建班组(CreateAsync
),更新班组(UpdateAsync
),删除班组(DeleteAsync
)。在下面的实例中实现
这里注意
using Abp.Application.Services.Dto;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.UI;
using Microsoft.EntityFrameworkCore;
using Practice2023.ClassGroups.Dto;
using Practice2023.Students;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Practice2023.ClassGroups
{
public class ClassGroupAppService : Practice2023AppServiceBase, IClassGroupAppService
{
//输入ClassGroup作为查询单条数据的类型?
public readonly IRepository<ClassGroup, long> _classGroupRepository;
public readonly IRepository<StudentClassGroup, long> _studentClassGroupRepository;
public ClassGroupAppService(
IRepository<ClassGroup, long> classGroupRepository,
IRepository<StudentClassGroup, long> studentClassGroupRepository)
{
_classGroupRepository = classGroupRepository;
_studentClassGroupRepository = studentClassGroupRepository;
}
/// <summary>
/// 获取班组信息
/// </summary>
public async Task<ClassGroupDto> GetAsync(long id)
{
//FirstOrDefaultAsync只找符合条件的第一个数据
var entity = await _classGroupRepository.FirstOrDefaultAsync(x => x.Id == id);
if (entity == null) return null;//return null的话不会报错,而是Swagger上显示null
//利用自动map把ClassGroup-->ClassGroupDto并return到Swagger上去
return ObjectMapper.Map<ClassGroupDto>(entity);
}
/// <summary>
/// 获取班组信息分页列表
/// </summary>
public async Task<PagedResultDto<ClassGroupDto>> GetPagedListAsync(PagedClassGroupResultRequestDto input)
{
//PagedClassGroupResultRequestDto有Keyword,ClassGroupType
//Keyword是希望部分字符串找Name
//通过这个Keyword字段告诉我们可以自己添加随意关键字用于后面辅助查询
var query = _classGroupRepository.GetAll()
.WhereIf(input.Type.HasValue, x => x.Type == input.Type)
.WhereIf(!input.Keyword.IsNullOrEmpty(), x => x.Name.Contains(input.Keyword));
var totalCount = await query.CountAsync();
var queryResult = await query.OrderByDescending(x => x.Id).PageBy(input).ToListAsync();
//queryResult是List<ClassGroup>类型
//PagedResultDto<T>.把泛型类型认定为ClassGroupDto,Map把List<ClassGroup>转为了List<ClassGroupDto>
//最终return PagedResultDto类型.Swagger应该能识别....
return new PagedResultDto<ClassGroupDto>(totalCount, ObjectMapper.Map<List<ClassGroupDto>>(queryResult));
}
private async Task CheckNameAsync(string name, long? id = null)
{
if (name.IsNullOrWhiteSpace()) throw new UserFriendlyException("名称不能为空!");//会显示在Swagger界面
//下面的WhereIf等价于.Where(id.HasValue ? x => x.Id != id : (Func<Item, bool>)null)
//当id.HasValue时进行Where操作.筛选出x.Id!=(NUll),(只可能是NULL).的所有数据即已存在于表中的数据
var isExists = await _classGroupRepository.GetAll().WhereIf(id.HasValue, x => x.Id != id).AnyAsync(x => x.Name == name);
if (isExists) throw new UserFriendlyException($"名称“{name}”已存在!");//会显示在Swagger界面
}
/// <summary>
/// 创建班组
/// </summary>
public async Task CreateAsync(CreateClassGroupDto input)
{
//Swagger界面只允许输入`Name`和`Type`<--CreateClassGroupDto.cs所导致的
await CheckNameAsync(input.Name);
//这种写法也可以
// var entity = new ClassGroup(input.Name, input.Type);
//或者使用自动Map函数将CreateClassGroupDto --> ClassGroup
var entity = ObjectMapper.Map<ClassGroup>(input);
//ClassGroup类型就可以直接Insert了?!
await _classGroupRepository.InsertAsync(entity);
}
/// <summary>
/// 更新班组
/// </summary>
public async Task UpdateAsync(UpdateClassGroupDto input)
{
//input只有Name和ClassGroupType<---UpdateClassGroupDto
await CheckNameAsync(input.Name, input.Id);
//这里的x是ClassGroup类型
var entity = await _classGroupRepository.FirstOrDefaultAsync(x => x.Id == input.Id);
if (entity == null) throw new UserFriendlyException("找不到信息!");
//Map方法用于将一个对象(input)UpdateClassDto的属性值映射到另一个对象(entity)ClassGroup的属性上。
ObjectMapper.Map(input, entity);
//entity是ClassGroup类型
await _classGroupRepository.UpdateAsync(entity);
}
/// <summary>
/// 删除班组
/// </summary>
public async Task DeleteAsync(long id)
{
var entity = await _classGroupRepository.FirstOrDefaultAsync(x => x.Id == id);
if (entity == null) return;
//先删掉副表
await _studentClassGroupRepository.DeleteAsync(x => x.ClassGroupId == id);
//再删主表
await _classGroupRepository.DeleteAsync(x => x.Id == id);
}
}
}
使用了Abp.Domain.Repositories;
命名空间的IRepository
。使用其带的各类操作.由于这里我们并不没有像Task类一样自定义了一个操作所以不需要再建之前的ITaskRepository.cs
,TaskRepository.cs
.
请注意每个函数的注释解释,可用于理解函数
需要再注意到
/// <summary>
/// 更新班组
/// </summary>
这个语句,可以在SwaggerUI界面添加中文注释:
二:CreateClassGroupDto.cs
,UpdateClassGroupDto
,PagedClassGroupResultRequestDto.cs
,ClassGroupMapProfile
,ClassGroupDto
:关于班级/小组类的数接口。前三者是用于Swagger的输入,第四者用于第五者与前三者的map操作。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Practice2023.ClassGroups.Dto
{
public class CreateClassGroupDto
{
public string Name { get; set; }
public ClassGroupType Type { get; set; }
}
}
using Abp.Application.Services.Dto;
namespace Practice2023.ClassGroups.Dto
{
public class UpdateClassGroupDto : EntityDto<long>
{
public string Name { get; set; }
public ClassGroupType Type { get; set; }
}
}
using Abp.Application.Services.Dto;
namespace Practice2023.ClassGroups.Dto
{
public class PagedClassGroupResultRequestDto : PagedResultRequestDto
{
public string Keyword { get; set; }
public ClassGroupType? Type { get; set; }
}
}
这里Keyword是自定义的Swagger输入字段,可用于辅助自定义函数,可随意增加或命名,详情见ClassGroupAppService.cs
的注释
using Abp.Application.Services.Dto;
namespace Practice2023.ClassGroups.Dto
{
public class PagedClassGroupResultRequestDto : PagedResultRequestDto
{
public string Keyword { get; set; }
public ClassGroupType? Type { get; set; }
}
}
using AutoMapper;
using Practice2023.Helpers;
namespace Practice2023.ClassGroups.Dto
{
public class ClassGroupMapProfile : Profile
{
public ClassGroupMapProfile()
{
//ClassGroup-->ClassGroup
//ClassGroup.Type.GetDescription()-->ClassGroupDto.TypeDecription
CreateMap<ClassGroup, ClassGroupDto>()
.ForMember(x => x.TypeDecription, e => e.MapFrom(x => x.Type.GetDescription()));
//CreateClassGroupDto-->ClassGroup
CreateMap<CreateClassGroupDto, ClassGroup>();
//UpdateClassGroupDto-->ClassGroup
CreateMap<UpdateClassGroupDto, ClassGroup>();
}
}
}
这里注意GetDescription()
是调用了ABP框架自建的EUNM函数(using Practice2023.Helpers;
命名空间)
using Abp.Application.Services.Dto;
using System;
namespace Practice2023.ClassGroups.Dto
{
public class ClassGroupDto : EntityDto<long>
{
public string Name { get; set; }
public ClassGroupType Type { get; set; }
public string TypeDecription { get; set; }
public DateTime CreationTime { get; set; }
}
}
三:IStudentAppService.cs
,StudentAppService
:关于班级/小组类的数接口
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Practice2023.Students.Dto;
using System.Threading.Tasks;
namespace Practice2023.Students
{
public interface IStudentAppService: IApplicationService
{
Task<StudentDto> GetAsync(long id);
Task<PagedResultDto<StudentDto>> GetPagedListAsync(PagedStudentResultRequestDto input);
Task CreateAsync(CreateStudentDto input);
Task UpdateAsync(UpdateStudentDto input);
Task DeleteAsync(long id);
}
}
using Abp.Application.Services.Dto;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.UI;
using Microsoft.EntityFrameworkCore;
using Practice2023.Students.Dto;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Practice2023.Students
{
public class StudentAppService : Practice2023AppServiceBase, IStudentAppService
{
private readonly IRepository<Student, long> _studentRepository;
private readonly IRepository<StudentExtra, long> _studentExtraRepository;
private readonly IRepository<StudentClassGroup, long> _studentClassGroupRepository;
public StudentAppService(
IRepository<Student, long> studentRepository,
IRepository<StudentExtra, long> studentExtraRepository,
IRepository<StudentClassGroup, long> studentClassGroupRepository)
{
_studentRepository = studentRepository;
_studentExtraRepository = studentExtraRepository;
_studentClassGroupRepository = studentClassGroupRepository;
}
/// <summary>
/// 获取学生信息
/// </summary>
public async Task<StudentDto> GetAsync(long id)
{
//_studentRepository是由Student类生成,当然有.Extra和.ClassGroups
//ThenInclude应该是基于ICollection等可迭代对象的Include操作,换在mysql语句中为InnerJoin
//ClassGroups在Student中定义为ICollection类型
var entity = await _studentRepository.GetAll()
.Include(x => x.Extra)
.Include(x => x.ClassGroups).ThenInclude(x => x.ClassGroup)
.FirstOrDefaultAsync(x => x.Id == id);
if (entity == null) return null;
//Student-->StudentDto-->Swagger自识别
return ObjectMapper.Map<StudentDto>(entity);
}
/// <summary>
/// 获取学生信息分页列表
/// </summary>
public async Task<PagedResultDto<StudentDto>> GetPagedListAsync(PagedStudentResultRequestDto input)
{
//PagedStudentResultRequestDto仅含
//KeyWord是筛查Name/Number/IdCardNumber可能某一部分可能含有的关键词
var query = _studentRepository.GetAll()
.Include(x => x.Extra)
.Include(x => x.ClassGroups).ThenInclude(x => x.ClassGroup)
.WhereIf(!input.Keyword.IsNullOrWhiteSpace(), x =>
x.Name.Contains(input.Keyword) ||
x.Number.Contains(input.Keyword) ||
x.IdCardNumber.Contains(input.Keyword));
//var test=query.ToQueryString();此语句用于输出query等价的MySql语句,可加断点查看test的内容
var totalCount = await query.CountAsync();
var queryResult = await query.OrderByDescending(x => x.Id).PageBy(input).ToListAsync();
return new PagedResultDto<StudentDto>(totalCount, ObjectMapper.Map<List<StudentDto>>(queryResult));
}
private async Task CheckIdCardNumberAsync(string idCardNumber, long? id = null)
{
if (idCardNumber.IsNullOrWhiteSpace()) return;
var isExists = await _studentRepository.GetAll().WhereIf(id.HasValue, x => x.Id != id).AnyAsync(x => x.IdCardNumber == idCardNumber);
if (isExists) throw new UserFriendlyException($"身份证号码“{idCardNumber}”已存在!");
}
private async Task CheckNumberAsync(string number, long? id = null)
{
if (number.IsNullOrWhiteSpace()) return;
var isExists = await _studentRepository.GetAll().WhereIf(id.HasValue, x => x.Id != id).AnyAsync(x => x.Number == number);
if (isExists) throw new UserFriendlyException($"学号“{number}”已存在!");
}
/// <summary>
/// 创建学生
/// </summary>
public async Task CreateAsync(CreateStudentDto input)
{
await CheckIdCardNumberAsync(input.IdCardNumber);
await CheckNumberAsync(input.Number);
var entity = new Student(input.Name, input.Sex, input.IdCardNumber, input.Number); // 也可以使用AutoMapper
entity.AddExtra(input.Extra.Extra1, input.Extra.Extra2, input.Extra.Extra3);
//input.ClassGroupIds类型是List<Long>
foreach (var classGroupId in input.ClassGroupIds)
{
entity.AddToClassGroup(classGroupId);
}
await _studentRepository.InsertAsync(entity);
}
/// <summary>
/// 更新学生
/// </summary>
public async Task UpdateAsync(UpdateStudentDto input)
{
await CheckIdCardNumberAsync(input.IdCardNumber, input.Id);
await CheckNumberAsync(input.Number, input.Id);
var entity = await _studentRepository.GetAll()
.Include(x => x.Extra)
.Include(x => x.ClassGroups).ThenInclude(x => x.ClassGroup)
.FirstOrDefaultAsync(x => x.Id == input.Id);
if (entity == null) return;
entity.Name = input.Name;
entity.Sex = input.Sex;
entity.IdCardNumber = input.IdCardNumber;
entity.Number = input.Number;
ObjectMapper.Map(input.Extra, entity.Extra);
var oriClassGroupIds = entity.ClassGroups.Select(x => x.ClassGroupId).ToList();
var newClassGroupIds = input.ClassGroupIds.Except(oriClassGroupIds);
var delClassGroupIds = oriClassGroupIds.Except(input.ClassGroupIds);
foreach (var newClassGroupId in newClassGroupIds)
{
entity.AddToClassGroup(newClassGroupId);
}
foreach(var delClassGroupId in delClassGroupIds)
{
entity.RemoveToClassGroup(delClassGroupId);
}
await _studentRepository.UpdateAsync(entity);
}
/// <summary>
/// 删除学生
/// </summary>
public async Task DeleteAsync(long id)
{
var entity = await _studentRepository.FirstOrDefaultAsync(x => x.Id == id);
if (entity == null) return;
await _studentClassGroupRepository.DeleteAsync(x => x.StudentId == entity.Id);
await _studentExtraRepository.DeleteAsync(x => x.StudentId == entity.Id);
await _studentRepository.DeleteAsync(x => x.Id == entity.Id);
}
}
}
四:CreateStudentDto.cs
,UpdateStudentDto.cs
,PagedStudentResultRequestDto.cs
,StudentMapProfile.cs
,StudentDto.cs
,StudentExtraDto.cs
,StudentClassGroupDto.cs
:类似
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Practice2023.Students.Dto
{
public class CreateStudentDto
{
/// <summary>
/// 姓名
/// </summary>
[Required]
public string Name { get; set; }
/// <summary>
/// 性别
/// </summary>
public string Sex { get; set; }
/// <summary>
/// 身份证号码
/// </summary>
public string IdCardNumber { get; set; }
/// <summary>
/// 学号
/// </summary>
public string Number { get; set; }
/// <summary>
/// 额外信息
/// </summary>
public StudentExtraDto Extra { get; set; } = new StudentExtraDto();
/// <summary>
/// 所在班组
/// </summary>
public List<long> ClassGroupIds { get; set; } = new List<long>();
}
}
using Abp.Application.Services.Dto;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Practice2023.Students.Dto
{
public class UpdateStudentDto : EntityDto<long>
{
/// <summary>
/// 姓名
/// </summary>
[Required]
public string Name { get; set; }
/// <summary>
/// 性别
/// </summary>
public string Sex { get; set; }
/// <summary>
/// 身份证号码
/// </summary>
public string IdCardNumber { get; set; }
/// <summary>
/// 学号
/// </summary>
public string Number { get; set; }
/// <summary>
/// 额外信息
/// </summary>
public StudentExtraDto Extra { get; set; } = new StudentExtraDto();
/// <summary>
/// 所在班组
/// </summary>
public List<long> ClassGroupIds { get; set; } = new List<long>();
}
}
using Abp.Application.Services.Dto;
namespace Practice2023.Students.Dto
{
public class PagedStudentResultRequestDto : PagedResultRequestDto
{
public string Keyword { get; set; }
}
}
using AutoMapper;
using Practice2023.Helpers;
namespace Practice2023.Students.Dto
{
public class StudentMapProfile : Profile
{
public StudentMapProfile()
{
CreateMap<Student, StudentDto>();
CreateMap<StudentExtra, StudentExtraDto>().ReverseMap();
CreateMap<StudentClassGroup, StudentClassGroupDto>()
.ForMember(x => x.Name, e => e.MapFrom(x => x.ClassGroup.Name))
.ForMember(x => x.Type, e => e.MapFrom(x => x.ClassGroup.Type))
.ForMember(x => x.TypeDescription, e => e.MapFrom(x => x.ClassGroup.Type.GetDescription()));
}
}
}
using Abp.Application.Services.Dto;
using System;
using System.Collections.Generic;
namespace Practice2023.Students.Dto
{
public class StudentDto : EntityDto<long>
{
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 性别
/// </summary>
public string Sex { get; set; }
/// <summary>
/// 身份证号码
/// </summary>
public string IdCardNumber { get; set; }
/// <summary>
/// 学号
/// </summary>
public string Number { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreationTime { get; set; }
/// <summary>
/// 额外信息
/// </summary>
public StudentExtraDto Extra { get; set; } = new StudentExtraDto();
/// <summary>
/// 所在班组
/// </summary>
public List<StudentClassGroupDto> ClassGroups { get; set; } = new List<StudentClassGroupDto>();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Practice2023.Students.Dto
{
public class StudentExtraDto
{
public string Extra1 { get; set; }
public string Extra2 { get; set; }
public string Extra3 { get; set; }
}
}
using Practice2023.ClassGroups;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Practice2023.Students.Dto
{
public class StudentClassGroupDto
{
public string Name { get; set; }
public ClassGroupType Type { get; set; }
public string TypeDescription { get; set; }
}
}
9:Practice2023DbContext.cs
:这是用于数据入库的文件
using Microsoft.EntityFrameworkCore;
using Abp.Zero.EntityFrameworkCore;
using Practice2023.Authorization.Roles;
using Practice2023.Authorization.Users;
using Practice2023.MultiTenancy;
using Practice2023.Students;
using Practice2023.ClassGroups;
namespace Practice2023.EntityFrameworkCore
{
public class Practice2023DbContext : AbpZeroDbContext<Tenant, Role, User, Practice2023DbContext>
{
/* Define a DbSet for each entity of the application */
public DbSet<Student> Students { get; set; }
public DbSet<StudentExtra> StudentExtras { get; set; }
public DbSet<ClassGroup> ClassGroups { get; set; }
public DbSet<StudentClassGroup> StudentClassGroups { get; set; }
public Practice2023DbContext(DbContextOptions<Practice2023DbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Student>(b =>
{
b.ToTable("Students");
b.Property(x => x.Name).IsRequired().HasMaxLength(StudentConsts.MaxNameLength);
b.Property(x => x.Sex).HasMaxLength(StudentConsts.MaxSexLength);
b.Property(x => x.IdCardNumber).HasMaxLength(StudentConsts.MaxIdCardNumberLength);
b.Property(x => x.Number).HasMaxLength(StudentConsts.MaxNumberLength);
b.HasOne(x => x.Extra).WithOne(x => x.Student).HasForeignKey<StudentExtra>(x => x.StudentId); // 一对一关系
b.HasMany(x => x.ClassGroups).WithOne(x => x.Student).HasForeignKey(x => x.StudentId); // 一对多关系
b.HasIndex(x => x.Name);
b.HasIndex(x => x.IdCardNumber);
b.HasIndex(x => x.Number);
});
modelBuilder.Entity<StudentExtra>(b =>
{
b.ToTable("StudentExtras");
b.Property(x => x.Extra1).HasMaxLength(StudentConsts.MaxExtra1Length);
b.Property(x => x.Extra2).HasMaxLength(StudentConsts.MaxExtra2Length);
b.Property(x => x.Extra3).HasMaxLength(StudentConsts.MaxExtra3Length);
});
modelBuilder.Entity<ClassGroup>(b =>
{
b.ToTable("ClassGroups");
b.Property(x => x.Name).IsRequired().HasMaxLength(ClassGroupConsts.MaxNameLength);
b.HasIndex(x => x.Name);
});
modelBuilder.Entity<StudentClassGroup>(b =>
{
b.ToTable("StudentClassGroups");
b.HasKey(x => new { x.StudentId, x.ClassGroupId });
});
}
}
}
这里在上面定义Dbset<T>
后就能自动更新数据。但是入库的表头名是用的原来类中的字段名。
用modelBuilder.Entity
可以更加体系性地入库.
这里注意语句
b.HasOne(x => x.Extra).WithOne(x => x.Student).HasForeignKey<StudentExtra>(x => x.StudentId); // 一对一关系
b.HasMany(x => x.ClassGroups).WithOne(x => x.Student).HasForeignKey(x => x.StudentId); // 一对多关系
涉及到了表间连接关系
10.DeBug与问题解答
Q1:泛型的用法
A1:
public class MyGenericClass<T>
{
private T value;
public MyGenericClass(T value)
{
this.value = value;
}
public T GetValue()
{
return value;
}
}
public class Program
{
static void Main(string[] args)
{
MyGenericClass<int> intClass = new MyGenericClass<int>(10);
int intValue = intClass.GetValue();
MyGenericClass<string> stringClass = new MyGenericClass<string>("Hello");
string stringValue = stringClass.GetValue();
Console.WriteLine(intValue); // 输出:10
Console.WriteLine(stringValue); // 输出:Hello
}
}
Q2:Inner join
A2:
内连接(Inner Join)是一种SQL操作,用于将两个或多个表中的行连接起来,只返回匹配的行。
假设我们有两个表:表A和表B。内连接将返回同时在表A和表B中有匹配的行。任何一边有NULL的都不会返回