配置实体与数据表之间的映射方式
- 有3种处理方式:1、特性(Data Annotation);2、链式API(Fluent API);3、Mapping;
- 特性,数据库表与实体类名称不一致,可以在类名称上加特性:
[Table("数据库表名称")]
;数据库表字段与类实体属性名称不一致,可以在属性上加特性:[Column("数据库表字段名称")]
,参考文末的EF 通过DataAnnotations配置属性和类型
//1 特性
[Table("T_Student")]
public partial class Student
{
[Key] //主键
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] //设置自增
//[DatabaseGeneratedAttribute(DatabaseGeneratedOption.None)]//非自增长,自增长为Identity
public int Id { get; set; }
[Required]//必填
[Column("SName")]//数据库表的字段名称
public string Name { get; set; }
[ForeignKey("category")] //外键
public int categoryid { get; set; }
}
- 链式API,数据库与类不一致(表名称、字段名称等)处理方法还有在
OnModelCreating()
方法里写链式API
//2 链式API
modelBuilder.Entity<Student>()
.ToTable("T_Student")
.Property(c => c.Name)
.HasColumnName("SName");
- Mapping,新增一个类并继承自
EntityTypeConfiguration<对应Model>
,命名规则通常:实体名称+Mapping,比如UserMapping,然后在其构造函数里用this调用方法进行配置,最后在OnModelCreating()
里添加:modelBuilder.Configurations.Add(new UserMapping());
OnModelCreating()
常见配置
- 初始化数据库上下文之前,将调用此方法,默认实现不执行任何操作;
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//throw new UnintentionalCodeFirstException();
//代表数据类修改了,会drop原数据库,重新创建新的数据库(原数据会全部丢失);
Database.SetInitializer<MyDbContext>(new DropCreateDatabaseIfModelChanges<MyDbContext>());
//默认 不存在就创建数据库
new CreateDatabaseIfNotExists<MyDbContext>();
//移除复数表名的契约,实体类与表名一致
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
//不创建EdmMetadata表
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
//禁用一对多级联删除
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
//表前缀
modelBuilder.Types().Configure(entity => entity.ToTable(AppConstant.Tableprefix + entity.ClrType.Name));
// 忽略列映射 Fluent API:NotMapped
modelBuilder.Entity<ScheduledEvents>().Ignore(p => p.ScheduleType);
//表前缀
modelBuilder.Types().Configure(entity => entity.ToTable(AppConstant.Tableprefix + entity.ClrType.Name));
//创建索引,为表CategoryModel的Name字段创建索引
modelBuilder.Entity<CategoryModel>().Property(p => p.Name).HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute()
{
IsUnique = false
}));
}
其他
- 在BaseDAL或BaseBLL用基类
DbContext
,DbContext.Set<T>
SaveChanges()
会开启一个事务,只要有一条语句异常,其他SQL就会都失败,即不会SaveChanges成功;dbContext.Users.Where.ToList()
,Where方法不会查询缓存数据,Find方法会优先查询缓存数据,没有再查询数据库,每次EF查询,都会缓存;AsNoTracking().ToList()
,AsNoTracking不跟踪,即不会再内存中clone,不能做删除修改动作;[DatabaseGenerated(DatabaseGeneratedOption.Identity)] //设置自增
,在实体- 主从表分别新增方法
- 用
using (TransactionScope trans = new TransactionScope())
包住2次SaveChanges()
,先插入主表SaveChanges()
,再插入子表SaveChanges()
,最后trans.Complete();
,如有异常,会自动rollback,TransactionScope
是windows系统支持的DTC,也支持多个dbContext实例一起SaveChanges; - 利用导航属性,主表
SaveChanges()
前,实例化所需子表,主表实例.子表属性赋值为子表实例List集合,再主表SaveChanges()
;
classRoom.Student = new List<Student>() { studend1, studend2 }; context.ClassRoom.Add(classRoom); context.SaveChanges();
- 用
- EF没有跟踪的实体要更新到数据库,需要
Attach
和State
配合
Context.Set<T>().Attach(t);//将数据附加到上下文,支持实体修改和新实体,重置为UnChanged
Context.Entry<T>(t).State = EntityState.Modified;
Context.SaveChanges();
参考资料:Entity Framework 索引
Entity Framework Code First关系映射约定
EF自动创建数据库
EF6 学习笔记(一):Code First 方式生成数据库及初始化数据库实际操作
EF 通过DataAnnotations配置属性和类型