Entity Framework 中的继承:每层表





5.00/5 (9投票s)
这是展示 Entity Framework 中继承的第一个文章。在本文中,我实现了“表分层”方法。
引言
这是 Entity Framework 文章系列。在我们之前的两篇文章中,我们学习了使用 Entity Framework 的各种方法以及在代码优先方法中处理数据库的各种策略。您可以在这里阅读:
在本文中,我们将学习如何在 Entity Framework 中处理继承。如果您对文章的目标不清楚,以下内容将有助于您理解:
我们知道继承是面向对象编程中的一个优秀概念,它提供了可重用的概念,这是软件设计原则最重要的实践之一。好的,我们将实现类级别的继承,这很好,但我们如何在数据库级别实现它呢?通常,我们知道派生类包含基类的所有属性,那么派生类表是否会包含基类表的所有属性?
我们将在这篇文章以及接下来的两篇文章中学习这些内容。在 Entity Framework 层面,有三种方法可以处理代码级别的继承。
- 表分层
- 类型分层
- 表分具体类型
在本文中,我们将理解“表分层”。我们知道继承只不过是一个分层概念,其中一个类从另一个类派生。它通过类和子类形成一个树状结构。表分层概念的意思是,每个分层只会创建一个表。例如,如果有一个类 A,并且类 B 从类 A 派生,那么对于该分层,数据库中只会创建一个表。所以基本概念是,一个分层将有一个表。看看下面的代码。
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace CodeFirst
{
public class Person
{
[Key]
public int PersonId { get; set; }
[Required]
[MaxLength(10)]
public string Name { get; set; }
public string surname { get; set; }
}
public enum FriendType
{
Close,
NotClose,
FamilyFriend
}
public class Friend : Person
{
public Int32 Person { get; set; }
public FriendType FriendType { get; set; }
}
public class TestContext : DbContext
{
public TestContext()
: base("DBConnectionString")
{
}
public DbSet<Person> Person { get; set; }
}
}
在此示例中,我们通过在 Friend
类中继承 Person
类来实现了一个分层。Entity Framework 足以在没有任何外部指令的情况下实现表分层。
现在让我们看看 TestContext
类。我们通过构造函数传递连接字符串,连接字符串需要在 web.config 文件中进行配置。在该类中,我们只初始化了 Person
类,而没有初始化 Friend
类。这就是 Entity Framework 的优势。如果我们填充基类,那么相关的派生类也会自动配置到一个表中。这是此示例在 web.config 文件中的连接字符串。
<connectionStrings> <add name="DBConnectionString" connectionString="Data Source=SERVERNAME;Initial Catalog=PersonDB;Integrated Security=true" providerName="System.Data.SqlClient"/> </connectionStrings>
一旦我们运行应用程序,我们将看到数据库已创建,并且表已生成,如下图所示。
如果我们仔细查看表结构,我们会看到一个 Discriminator 列。为什么创建了这个额外的列?我们在代码中没有实现它。Entity Framework 聪明地创建了该字段来区分不同的表。概念是这样的:Person
对象和 Friend
对象都将保存在同一个表中,那么我们如何区分它们呢?我们如何知道特定行中的数据是用于 Person
对象还是 Friend
对象?为了区分它们,引入了 Discriminator 列。这是我们保存 Person
类对象的地方
static void Main(string[] args) { using (var ctx = new TestContext()) { //Save Object of Person table. ctx.Person.Add(new Person { Name = "Sourav", surname = "Kayal" }); ctx.SaveChanges(); } }
看看表数据,我们看到“Person”已保存在 Discriminator 列的值中,所以记录包含 Person
类的对象。
现在,我们将在同一个表中保存 Friend
类的对象。看看下面的代码
static void Main(string[] args) { using (var ctx = new TestContext()) { //Save Object of Person table. ctx.Person.Add(new Friend { Name = "Foo", surname = "Bar" ,PersonId = 1,FriendType =FriendType.Close}); ctx.SaveChanges(); } }
这里数据已保存在表中,并且 Discriminator 列的值为 Friend。
自定义“Discriminator”列
您可能会想:是否可以更改默认的“Discriminator”列名?或者更改其值?是的,这是可能的。使用 Fluent API 我们可以做到。看看修改后的代码。
public class TestContext : DbContext
{
public TestContext()
: base("DBConnectionString")
{
}
public DbSet<Person> Person { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.Map<Friend>(m => m.Requires("ObjectType").HasValue("FriendType"));
modelBuilder.Entity<Person>()
.Map<Person>(m => m.Requires("ObjectType").HasValue("PersonType"));
}
}
现在,当我们保存某些对象的时。例如,Friend
对象将保存值“Friend Type”,与之前的示例中的“Friend”不同。让我们尝试使用下面的代码保存数据。
static void Main(string[] args)
{
using (var ctx = new TestContext())
{
ctx.Person.Add(new Friend { Name = "Foo", surname = "Bar" ,PersonId = 1,FriendType =FriendType.Close});
ctx.SaveChanges();
}
}
看看数据库结构。我们看到“FriendType
”已保存在表中,因为我们保存了 Friend
类的对象。
现在,我们将尝试在表中保存 Person
类的对象。这是一个示例代码
static void Main(string[] args)
{
using (var ctx = new TestContext())
{
ctx.Person.Add(new Person { Name = "Ram", surname = "Kumar" });
ctx.SaveChanges();
}
}
现在,表中显示的值是“Person Type”。
所以我们已经了解了表的创建概念和 Discriminator 列的概念,现在我们将学习从表中提取数据。要从这样的表中提取数据,我们可以使用多态查询和非多态查询。尝试一下
多态查询
根据概念,它将在单个查询中拉取所有相关的分层数据。在这里,我们拉取所有与 Person
对象相关的数据。现在,由于 Friend
是从 Person
派生的,Friend 的信息会自动拉取。这是一个示例代码。
using (var ctx = new TestContext())
{
var data = from tab in ctx.Person select tab;
List<Person> persons= data.ToList();
}
看到表中的两条记录已被提取,所以我们同时获得了 Friend
和 Person
对象。
非多态查询
在此查询中,我们将提取一个特定的列值。这里我们只拉取“Friend
”对象。
using (var ctx = new TestContext())
{
//Get All Friend From Person Table
var data = from tab in ctx.Person.OfType<Friend>() select tab;
List<Friend> persons = data.ToList();
}
我们只得到一个对象。
总结
我们已经学习了如何在 Entity Framework 中实现“表分层”概念来处理继承。希望本文能帮助您在 Entity Framework 的学习道路上更进一步。在接下来的文章中,我们将理解 Entity Framework 中的另外两种继承策略。环境。