efcore 实体配置_asp.net core系列 28 EF模型配置(字段,构造函数,拥有实体类型)

一. 支持字段

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

1.1 约定

public class Blog

{

// _

private string _url;

public int BlogId { get; set; }

public string Url

{

get { return _url; }

set { _url = value; }

}

}

1.2 Fluent API

modelBuilder.Entity()

.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 Posts { get; } = new List();

}

别外使用私有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 Posts { get; } = new List();

}

protected override void OnModelCreating(ModelBuilder modelBuilder)

{

modelBuilder.Entity(

b =>

{

b.HasKey("_id");

b.Property(e => e.Author);

b.Property(e => e.Name);

});

}

2.2 注入服务

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

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

ILazyLoader- 延迟加载服务

Action- 一个延迟加载的委托

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 Posts { get; set; }

//获取帖子数量

public int PostsCount

=> Posts?.Count

?? Context?.Set().Count(p => Id == EF.Property(p, "BlogId"))

?? 0;

}

有一些需要注意:

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

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

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

三.拥有的实体类型

该功能是在 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 options)

: base(options)

{ }

public DbSet Order { get; set; }

}

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

image

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

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

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

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

3.2 隐含键

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

3.3 拥有的集合类型

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

public class Distributor

{

public int Id { get; set; }

public ICollection ShippingCenters { get; set; }

}

modelBuilder.Entity().OwnsMany(p => p.ShippingCenters, a =>

{

// 给ShippingCenters表设置一个主键

a.Property("Id");

//给ShippingCenters表设置一个外键

a.HasForeignKey("DistributorId");

//设置复合主键

a.HasKey("DistributorId", "Id");

});

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

image

设计限制:

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

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

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

参考文献:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我理解了你的问题。关于 Hangfire、MySQL 和 ASP.NET Core 3.1 的使用,我可以给出一些异常解决的建议。 首先,确保你已经按照官方文档正确地安装和配置了 Hangfire 和 MySQL。然后,根据你遇到的异常,尝试以下解决方法: 1. "Could not load file or assembly 'MySql.Data' or one of its dependencies" 异常 这个异常通常是由于缺少 MySQL 数据库驱动程序引起的。你需要在项目中添加对 MySQL 数据库驱动程序的引用。可以通过 NuGet 包管理器来安装 MySQL.Data。 2. "Specified key was too long; max key length is 767 bytes" 异常 这个异常是由于 MySQL 的索引长度限制引起的。解决方法是,在你的 DbContext 类中覆盖 OnModelCreating 方法,将所有字符串属性的最大长度设置为 255。 ``` protected override void OnModelCreating(ModelBuilder modelBuilder) { foreach (var property in modelBuilder.Model.GetEntityTypes() .SelectMany(t => t.GetProperties()) .Where(p => p.ClrType == typeof(string))) { property.SetMaxLength(255); } } ``` 3. "MySqlException: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding" 异常 这个异常通常是由于 MySQL 连接超时引起的。解决方法是,在连接字符串中添加 Connection Timeout 参数,例如: ``` "Server=myServerAddress;Database=myDataBase;Uid=myUsername;Pwd=myPassword;Connection Timeout=60;" ``` 这将使连接超时时间为 60 秒。 希望这些解决方法能帮助你解决异常问题。如果你还有其他问题,请随时问我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值