2020-03-28 EFCore 的教程 -- 提纲2

2020-05-17  本文已影响0人  daiwei_9b9c
  1. EFCore入门

    • 配置数据库连接字符串
    • EFCore 如何自动获知数据库主键
    • 将项目的变动更新到数据库
    • 安装 EFCore 的数据库驱动
  2. 索引

    • 索引 ( HasIndex ) / 唯一索引 ( IsUnique ) / 包含附加字段的索引 ( IncludeProperties) / 指定筛选条件的索引 ( HasFilter )
  3. 表之间的关系

    • 主体实体 / 主体健 / 相关实体 / 外键
    • 导航属性 / 集合导航属性 / 引用导航属性 / 反向导航属性
    • 关系 / 自引用关系
    • 不使用 FluentApi 定义时 -- 完全定义关系 / 单个导航属性
    • FluentApi ( HasOne / WithMany / WithOne / HasMany )
    • 什么情况下需要使用 FluentAPI
    • 影子外键
  4. InverseProperty 标注的用途

  5. 阴影属性

    • 定义阴影字段
    • 访问阴影字段
  6. 继承

    • 非抽象类以及其子类只支持对应到单个表, 使用鉴别器列区分行所对应的实体类型(Discriminator), 使用 Table 标注无效
    • 抽象类的直接子类支持多个类对应到多个表
    • 同一个表的不同类型有相同属性时,默认将创建多列; 如果属性类型相同,可以通过 FluentAPI 定义属性对应到同一列;
    • 考虑如下情形, 非抽象类 (Blog) --- 抽象类 ( AbstractBlog ) --- 非抽象类 (RssBlog ) 会如何创建表?
      ** 还是只会创建 Blog 表并带有 鉴别器列
  7. 序列

注意,数据库不同时,从序列取值的语法也不同,
例如 ORACLE OrderNumbers.NEXTVAL

modelBuilder.HasSequence<int>("OrderNumbers", schema: "shared")
        .StartsAt(1000)
        .IncrementsBy(5);
modelBuilder.Entity<Order>()
        .Property(o => o.OrderNo)
        .HasDefaultValueSql("NEXT VALUE FOR shared.OrderNumbers");
  1. 字段映射 / 非空构造函数的实体 ( 只读属性 ) / 服务注入到实体类的构造函数

  1. 值转换器 和 值比较器

  1. 表拆分
    https://docs.microsoft.com/zh-cn/ef/core/modeling/table-splitting]
modelBuilder.Entity<Order>()Property<byte[]>("Version").IsRowVersion().HasColumnName("Version");
modelBuilder.Entity<DetailedOrder>().Property(o => o.Version).IsRowVersion().HasColumnName("Version");
                ......

                var order = context.Orders.First();
                var detailOrder = context.DetailedOrders.First();
                detailOrder.BillingAddress = "广州市";
                context.SaveChanges();  <== 这儿会查询新的 令牌, 并更新到 order 中
                order.Status = OrderStatus.Shipped;
                context.SaveChanges();
  1. 从属实体类型
    https://docs.microsoft.com/zh-cn/ef/core/modeling/owned-entities
    • 从属实体类型表示某一个类型的实例被其他类型的实例所拥有
    • FluentAPI: OwnsOne, 从属实体类型可以单独映射到另外一个表
public class DetailedOrder
{
    public int Id { get; set; }
    //通过 FluentAPI表示此为从属类型,并且映射到单独表
    //查询时总是会把 OrderDetails 表中的数据查询出来
    public OrderDetails OrderDetails { get; set; } ,    
}
public class OrderDetails
{
   // 不注释将创建 OrderId 的外键字段,
   // 注释后将创建 DetailOrderId 的外键字段
   // public DetailedOrder Order { get; set; } 

   // 嵌套的从属实体类型, 默认下创建 BillingAddress_Street 和 BillingAddress_City 2个字段
   // 通过 FluentAPI 将上面2个字段变为了 BillStreet 和 BillCity 
    public StreetAddress BillingAddress { get; set; } 

   // 嵌套的从属实体类型, 将创建 ShippingAddress_Street 和 ShippingAddress_City 2个字段
    public StreetAddress ShippingAddress { get; set; }
}
[Owned]
public class StreetAddress
{
        public string Street { get; set; }
        public string City { get; set; }
}
....
modelBuilder.Entity<DetailedOrder>().OwnsOne(p => p.OrderDetails, od =>
{
         od.ToTable("OrderDetails");  
         od.OwnsOne(x => x.BillingAddress, bi =>
                 {
                     bi.Property(y => y.Street).HasColumnName("BillStreet");
                     bi.Property(y => y.City).HasColumnName("BillCity");
                 });
                //下面方法抛出异常
                //od.Property(x => x.ShippingAddress.City).HasColumnName("ShipAddr_City");
 });
public class Distributor
 {
     public int Id { get; set; }

     // 将创建 Distributor_ShippingCenters 表, 将在查询 Distributor 中自动查询词表
     // Distributor_ShippingCenters  会自动创建 DistributorId (外键关联), Id ( 表主键), 
     // Street, City ( StreetAddress 实体中的属性列 ) 
     public ICollection<StreetAddress> ShippingCenters { get; set; } 
 }
                context.DetailedOrders.First().OrderDetails.BillingAddress.Street = "怡雅街";
                context.Distributors.First().ShippingCenters.First().Street = "ABC";
  1. 无主键实体类型
    • [KeyLess] 或者 modelBuilder.Entity<BlogPostsCount>().HasNoKey();
    • EFCore 不会追踪实体的变更, 只能作为只读数据源
    • 可以通过 ToTable 映射到表 或者 ToView 映射视图
    • 可以变更映射列
        {
            eb.HasNoKey();
            eb.ToView("View_BlogPostCounts");
            eb.Property(v => v.BlogName).HasColumnName("Name");
        });
  1. 根据 DbContext 属性参数化实体
  // 实现 IModelCacheKeyFactory 接口的类
  public class DynamicModelCacheKeyFactory : IModelCacheKeyFactory
 {
     //根据 DbContext 获取缓存的 Key
     //当 DbContext 是 DynamicContext 类型实例时,
     //返回 带有 (context.Type, UseIntProperty) 的一个结构作为 Key
     //这样, 当 UseIntProperty 不同时,返回的 Key 也不同;
     public object Create(DbContext context)
        => context is DynamicContext dynamicContext
            ? (context.GetType(), dynamicContext.UseIntProperty) 
            : (object)context.GetType();
 }
DynamicContext .Cs
// optionsBuilder 中注册  DynamicModelCacheKeyFactory 类型为  IModelCacheKeyFactory 接口的提供者
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .ReplaceService<IModelCacheKeyFactory, DynamicModelCacheKeyFactory>();

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    if (UseIntProperty)  // 这儿,在 ( DynamicContext , true) 作为 Key 时会执行一次
    {
        modelBuilder.Entity<ConfigurableEntity>().Ignore(e => e.StringProperty);
    }
    else  // 这儿,在 ( DynamicContext , false) 作为 Key 时会执行一次
    {
        modelBuilder.Entity<ConfigurableEntity>().Ignore(e => e.IntProperty);
    }
}
  1. 空间数据
    https://docs.microsoft.com/zh-cn/ef/core/modeling/spatial
下面的 srid 指定 4326, 指的是 WGS 84,是 GPS 和其他地理系统中使用的标准。
x 表示经度, y 表示纬度,  客户端计算的值(距离,长度等)将是度数;
var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326);
var currentLocation = geometryFactory.CreatePoint(-122.121512, 47.6739882);
上一篇下一篇

猜你喜欢

热点阅读