一. 支持字段

EF允许读取或写入字段而不是一个属性。在使用实体类时,用面向对象的封装来限制或增强应用程序代码对数据访问的语义时,这可能很有用。无法使用数据注释配置。除了约定,还可以使用Fluent API为属性配置支持字段。

  1.1 约定

public class Blog
{
// _<camel-cased property name>
private string _url; public int BlogId { get; set; } public string Url
{
get { return _url; }
set { _url = value; }
}
}

  1.2 Fluent API

modelBuilder.Entity<Blog>()
.Property(b => b.Url)
.HasField("_validatedUrl"); public class Blog
{
private string _validatedUrl; public string Url
{
get { return _validatedUrl; }
} public void SetUrl(string url)
{
//...
_validatedUrl = url;
}
}

二. 构造函数

  从开始 EF Core 2.1,可以定义带参数的构造函数,并在创建实体实例时让EF Core调用此构造函数。构造函数参数可以绑定到映射属性,或绑定到各种服务,以方便延迟加载等行为。

  2.1  带参的构造函数

    下面代码演示带参数的构造函数,并且设置只读属性,外部调用该类时,只能通过构造函数传入实体值。

public class Blog
{
public Blog(int id, string name, string author)
{
Id = id;
Name = name;
Author = author;
} public int Id { get; private set; } public string Name { get; private set; }
public string Author { get; private set; } public ICollection<Post> Posts { get; } = new List<Post>();
}

    别外使用私有setter的另一种方法是使属性真正只读,并在OnModelCreating中添加更明确的映射。

public class Blog
{
private int _id; public Blog(string name, string author)
{
Name = name;
Author = author;
} public string Name { get; }
public string Author { get; } public ICollection<Post> Posts { get; } = new List<Post>();
} protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>(
b =>
{
b.HasKey("_id");
b.Property(e => e.Author);
b.Property(e => e.Name);
});
}

  

  2.2 注入服务

    EF Core还可以将“服务”注入实体类型的构造函数中。例如,可以注入以下内容:

    DbContext - 当前上下文实例,也可以作为派生的DbContext类型键入

    ILazyLoader- 延迟加载服务

    Action<object, string>- 一个延迟加载的委托

     IEntityType - 与此实体类型关联的EF Core元数据

    例如,注入的DbContext可用于选择性地访问数据库以获得关于相关实体的信息而无需全部加载它们。在下面的示例中,这用于获取Blog博客中的Posts帖子数量:

public class Blog
{
public Blog()
{
} private Blog(BloggingContext context)
{
Context = context;
} private BloggingContext Context { get; set; } public int Id { get; set; }
public string Name { get; set; }
public string Author { get; set; } public ICollection<Post> Posts { get; set; } //获取帖子数量
public int PostsCount
=> Posts?.Count
?? Context?.Set<Post>().Count(p => Id == EF.Property<int?>(p, "BlogId"))
?? ;
}

    有一些需要注意:

     (1)构造函数是私有的,因为它只由EF Core调用,并且还有另一个通用的公共构造函数。

      (2)使用注入服务的代码(即EF上下文)防御它为null,处理EF Core未创建实例的情况。

      (3)因为服务存储在读或写属性中,所以当实体附加到新的上下文实例时,它将被重置。

    2.2示例演示,没有成功,Blog带参的构造函数为私有,无法调用, context上下文总为null,以后在了解。

三.拥有的实体类型

  该功能是在 EF Core 2.0 中的新增功能。是指:当一个实体类中包含导航属性(实体类型引用属性),并对导航属性进行建模,这个导航属性类被称为“拥有实体类型”。而包含“拥有实体类型”的类叫:所有者。

  3.1 显示配置

    EF Core中的所有实体类型永远不会按照约定包含在模型中。可以使用OwnsOne在(使用EF Core 2.1中的新增功能)OnModelCreating中使用或用注释类型OwnedAttribute将类型配置为拥有类型。

    下面示例中StreetAddress是一个没有标识属性的类型。 它用作 Order 类型的属性来指定特定订单的发货地址。

//拥有实体类型
[Owned]
public class StreetAddress
{
public string Street { get; set; }
public string City { get; set; }
} //所有者
public class Order
{
public int Id { get; set; } public StreetAddress ShippingAddress { get; set; }
} public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{ }
public DbSet<Order> Order { get; set; }
}

    使用EF基于数据模型(Order)创建数据库,如下图所示。

        

    还可以使用该OwnsOne方法在OnModelCreating指定ShippingAddress属性,是Order实体类型的拥有实体,并根据需要配置其他方面。

    modelBuilder.Entity<Order>().OwnsOne(p => p.ShippingAddress);

    如果ShippingAddress属性在Order实体中为私有属性,则可以使用的字符串版本OwnsOne方法:

    modelBuilder.Entity<Order>().OwnsOne(typeof(StreetAddress), "ShippingAddress");

  3.2 隐含键

    OwnsOne通过引用导航配置或发现的拥有类型始终与所有者具有一对一的关系,因此拥有实体不需要自己的键值,因为外键值是唯一的。在前面的示例中,StreetAddress类型不需要定义键属性。拥有实体类型的实例键值与所有者实例的键值相同。

  3.3 拥有的集合类型

    要配置拥有的集合类型,使用OwnsManyOnModelCreating中使用。但是,主键不会按约定配置,因此需要明确指定。下面代码演示拥有的集合类型的关键代码。

    public class Distributor
{
public int Id { get; set; }
public ICollection<StreetAddress> ShippingCenters { get; set; }
}   modelBuilder.Entity<Distributor>().OwnsMany(p => p.ShippingCenters, a =>
{
// 给ShippingCenters表设置一个主键
a.Property<int>("Id");
//给ShippingCenters表设置一个外键
a.HasForeignKey("DistributorId");
//设置复合主键
a.HasKey("DistributorId", "Id");
});

    使用EF基于数据模型(Distributor)创建数据库,如下图所示(一对多的关系)。Distributor_ShippingCenters表的ID为主键,DistributorId为外键。

    设计限制:

    对于拥有的实体类型无法创建DbSet<T>。

    在 ModelBuilder中调用Entity<T>()时,T不能是拥有的实体类型。

 关于拥有的实体类型的更多介绍参考官方文档,这里不是介绍。关于“EF模型配置系列”的很多功能,都是基于code first模式。

  参考文献:

    官方文档:EF支持字段

           EF构造函数

           EF拥有的实体类型

           拥有实体类型的完整案例

asp.net core系列 28 EF模型配置(字段,构造函数,拥有实体类型)的更多相关文章

  1. asp.net core系列 29 EF模型配置(查询类型,关系数据库建模)

    一.查询类型 此功能是EF Core 2.1中的新功能. EF Core除了实体类型之外,EF Core模型还可以包含查询类型,这些查询类型是针对“未映射到实体类型”的数据获取.比如视图,或只读数据表 ...

  2. asp.net core系列 23 EF模型配置(概述, 类型和属性的包含与排除)

    一.模型配置概述 EF使用一组约定基于实体类的定义来构建模型. 可指定其他配置以补充或替代约定的内容.本系列介绍的配置可应用于面向任何数据存储的模型,以及面向任意关系数据库时可应用的配置. 数据库提供 ...

  3. asp.net core系列 27 EF模型配置(索引,备用键,继承)

    一.索引 索引是许多数据存储中的常见概念.虽然它们在数据存储中的实现可能会有所不同,但它们可用于更有效地基于列(或列集)进行查找.按照约定,用作外键每个属性 (或组的属性) 会自动创建索引.无法使用数 ...

  4. asp.net core系列 25 EF模型配置(隐藏属性)

    一. 隐藏属性概述 隐藏属性也叫影子属性,该属性不是在.net实体类中定义的属性,而是在EFCore模型中为该实体类型定义的属性.这些属性的值和状态完全在变更跟踪器中维护.它有二个功能:(1)当数据库 ...

  5. asp.net core系列 26 EF模型配置(实体关系)

    一.概述 EF实体关系定义了两个实体互相关联起来(主体实体和依赖实体的关系,对应数据库中主表和子表关系). 在关系型数据库中,这种表示是通过外键约束来体现.本篇主要讲一对多的关系.先了解下描述关系的术 ...

  6. asp.net core系列 24 EF模型配置(主键,生成值,最大长度,并发标记)

    一.主键 键用作每个实体实例的主要唯一标识符. 使用关系数据库时,这会映射到主键的概念. 还可以配置不是主键的唯一标识符.按照约定,名为 Id 或 <type name>Id 的属性会配置 ...

  7. asp.net core系列 30 EF管理数据库架构--必备知识 迁移

    一.管理数据库架构概述 EF Core 提供两种主要方法来保持 EF Core 模型和数据库架构同步.一是以 EF Core 模型为基准,二是以数据库为基准. (1)如果希望以 EF Core 模型为 ...

  8. asp.net core系列 31 EF管理数据库架构--必备知识 反向工程

    一.   反向工程 反向工程是基于数据库架构,生成的实体类和DbContext类代码的过程,对于Visual Studio开发,建议使用PMC.对于其他开发环境,请选择.NET Core CLI工具( ...

  9. asp.net core 系列 22 EF(连接字符串,连接复原,DbContext)

    一.连接字符串 在上二篇中,ASP.NET Core 应用程序连接字符串是写死在ConfigureServices代码中,下面介绍通过配置来实现.连接字符串可以存储在 appsettings.json ...

随机推荐

  1. Runc 简介

    RunC 是什么? RunC 是一个轻量级的工具,它是用来运行容器的,只用来做这一件事,并且这一件事要做好.我们可以认为它就是个命令行小工具,可以不用通过 docker 引擎,直接运行容器.事实上,r ...

  2. Myeclipse按包装SVN

    最简单步骤:把features和plugins直接放到Myeclipse安装包的dropins中,从新启动eclipse即可 features和plugins下载地址:http://pan.baidu ...

  3. 外观模式facade

    一句话,多外呈现一个统一接口,内部的具体实现不关心. 外观模式facade,其实就是在调用者 与 被调用的实现层 之间加一层 facade层,不管内部如何实现, 用什么技术 方法实现,对外呈现的外观是 ...

  4. 2017年的golang、python、php、c++、c、java、Nodejs性能对比[续]

    2017年的golang.python.php.c++.c.java.Nodejs性能对比[续] 最近忙,这个话题放了几天,今天来个续集.   上篇传送门: 2017年的golang.python.p ...

  5. SpringCloud实战-Zuul网关服务

    为什么需要网关呢? 我们知道我们要进入一个服务本身,很明显我们没有特别好的办法,直接输入IP地址+端口号,我们知道这样的做法很糟糕的,这样的做法大有问题,首先暴露了我们实体机器的IP地址,别人一看你的 ...

  6. Ubuntu 18.04 on Windows 10 更改 Oh-My-Zsh agnoster 主题下的目录背景色

    题外话 我的 MacBook Pro 已经使用了6年多的时间,尽管作为一个 .NET 程序员绝大部分时间都是在 Windows 下工作,直到 .NET Core 的逐步成熟.要说 Mac OS,最满意 ...

  7. vritualenv虚拟环境迁移

    vritualenv虚拟环境迁移的简单步骤: 1.进入原虚拟环境env1,然后执行pip freeze > requirements.txt将包依赖信息保存在requirements.txt文件 ...

  8. 【ShoppingWebCrawler】-基于Webkit内核的爬虫蜘蛛引擎概述

    写在开头 在各个电商平台发展日渐成熟的今天.很多时候,我们需要一些平台上的基础数据.比如:商品分类,分类下的商品详细,甚至业务订单数据.电商平台大多数提供了相应的业务接口.允许ISV接入,用来扩展自身 ...

  9. 在docker上运行.net core程序

    一.安装docker及镜像 1.在centos上安装docker,命令如下: # yum install docker 2.让docker随机启动: # service docker start# c ...

  10. bzoj 4501 旅行

    01分数规划+最大权闭合子图 倒拓扑序处理每个节点 $$f[x]=\frac{\sum{f[v]}}{n}+1$$ 二分答案$val$ 只需要判断是否存在$\sum{f[v]}+1-val>0$ ...