asp.net core系列 28 EF模型配置(字段,構造函數,擁有實體類型)
一. 支援字段
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"))
?? 0;
}
有一些需要注意:
(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)建立資料庫,如下圖所示。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIx0DciV2dmADM30zd-cmbw5CRzUCRzUydaVnQux0djRkT5llaOp3Yq1EdjRlT61EVONTRq5EeBpWT5FEVPhXQq1EdBpmTxUEVOhHOp10drRVT3lkeMdXWU5EeVRVT2NmMiNnSywEd5ITW110MaZHetlVdO1GT0UERNl3YXJGc5kHT20ESjBjUIF2Lc12bj5SYphXa5VWen5WY35iclN3Ztl2Lc9CX6MHc0RHaiojIsJye.png)
還可以使用該
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 擁有的集合類型
要配置擁有的集合類型,使用
OwnsMany
在
OnModelCreating
中使用。
但是,主鍵不會按約定配置,是以需要明确指定。下面代碼示範擁有的集合類型的關鍵代碼。
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為外鍵。
關于擁有的實體類型的更多介紹參考官方文檔,這裡不是介紹。關于“EF模型配置系列”的很多功能,都是基于code first模式。
參考文獻:
官方文檔:EF支援字段
EF構造函數
EF擁有的實體類型
擁有實體類型的完整案例
posted on 2019-02-20 17:47 花陰偷移 閱讀(...) 評論(...) 編輯 收藏