1. 程式人生 > >.NET - EntityFramework 實體關系數據模型

.NET - EntityFramework 實體關系數據模型

節點 旅行 cal pin identity asm 最小 var 並且

EntityFramework 實體關系數據模型(DO.NET Entity Framework)

ADO.NET Entity Framework 是微軟以 ADO.NET 為基礎所發展出來的對象關系對應 (O/R Mapping) 解決方案。該框架曾經為.NET Framework的一部分,但version 6之後從.NET Framework分離出來。

在項目中使用Entity Framework

要得到最高版本的Entity Framework 程序包,可以通過擴展與更新或者右擊項目-引用-管理NuGet程序包。

技術分享技術分享

創建Entity實體關系模型

右擊項目 - 添加 - 數據 - ADO.NET實體數據模型

技術分享

來自數據庫的EF設計器:通過已經事先創建的數據庫和表,EF框架自動根據數據庫生成表實體。

空EF設計器模型:通過EF設計器的可視化界面設計實體關系圖,EF框架自動根據關系圖生成數據庫、表和對應的實體類。

Code First模型:通過全手工創建實體,運行代碼後自定生成數據庫和表。

添加完成後在項目中會包含一個後綴為edmx文件,此文件描述模型的架構。這三個文件分別是模型的XML表示,數據庫構架的XML表示、映射表與實體的關系的XML表示。

xxx.context.tt(數據庫操作上下文)

xxx.tt(實體模型)

Code First模式

DbContext類(System.Data.Entity.DbContext)

這是一個操作實體的上下文對象,它比ObjectContex更輕量級,推薦使用DbContext。DbContext內部維護了數據庫連接、管理實體數據、生成數據庫操作語句、將數據持久化到數據庫。它包含所有的實體對象的集合(可查詢數據集),通過它的泛型集合屬性DbSet<T>存儲這些數據集。你所創建的類是如何成為Entity實體的呢?很簡單,完成以下三步:

1.創建一個類庫,命名為DataAccess,用以表示數據訪問層,創建一個BreakAwayContext的類,使其從DbContext派生。鍵入以下代碼:

技術分享 using System.Data.Entity;
using
Model;


namespace DataAcess
{
public class BreakAwayContext : DbContext
{
public BreakAwayContext ( ) : base ( "name=DBConnection" ) { } //name=配置文件中的數據庫連接字符串的名稱
public DbSet<Destination> Destinations { get; set; } //你創建的實體類Destination,實體代表了一張表,此處通過DbSet泛型集合表示該表的所有記錄
public DbSet<Lodging> Lodgings { get; set; } //你創建的實體類Lodging,實體代表了一張表,此處通過DbSet泛型集合表示該表的所有記錄

//使用此靜態構造函數指定數據庫的初始化方式,無論如何請先關閉打開的數據庫、關閉vs中的服務器資源管理器中的數據庫連接,否則以下任務不會完成
static BreakAwayContext ( )
{
Database.SetInitializer ( new CreateDatabaseIfNotExists<BreakAwayContext> ( ) ); //默認,參數可為null,當數據庫不存在時,自動創建數據庫
Database.SetInitializer ( new DropCreateDatabaseAlways<BreakAwayContext> ( ) ); //無論怎樣,刪除同名數據庫,再重新創建
Database.SetInitializer ( new DropCreateDatabaseIfModelChanges<BreakAwayContext> ( ) ); //如果實體模型發生改變,則先刪除同名數據庫,再重新創建
}
}
} DataAccess

2.創建一個類庫,命名為Model,用以表示實體層,創建兩個實體類:Destination和Lodging。前者表示旅行的目的地,後者表示住宿。鍵入以下代碼:

技術分享 namespace Model
{
/// <summary>
/// 目的地
/// </summary>
public class Destination
{
public int DestinationId { get; set; }
public string Name { get; set; }
public string Country { get; set; }
public string Description { get; set; }
public byte [ ] Photo { get; set; }
//Lodgings集合是Lodging類,該表會被識別為外鍵表,因為這表示了一個Destination(目的地)對應多個Lodgings(住宿)的關系。
public List<Lodging> Lodgings { get; set; }
}
} Destination 技術分享 namespace Model
{
/// <summary>
/// 住宿
/// </summary>
public class Lodging
{
public int LodgingId { get; set; }
public string Name { get; set; }
public string Owner { get; set; }
public bool IsResort { get; set; }
//作為外鍵引用了Destination表的主鍵,此處可以寫成public Destination Destination,效果是一樣的,都會被識別為對Destination表的主鍵的引用
public int DestinationId { get; set; }
}
} Lodging

3.創建一個控制臺應用程序,命名為BreakAwayConsole,用以表示顯示層。添加對Entity framework的引用,這樣會自動在App.config中生成默認的數據庫配置信息節點:<entityFramework>,將其全部刪除,再添加一個ConnectionString,configSections好像必須是configuration的第一個配置節,所以ConnectionString配置節只能放在configSections後面。

技術分享 <?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name="DBConnection"
connectionString="Data Source=(local); Database=stuEntity; User ID=sa; Password=123456; MultipleActiveResultSets=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration> app.config

4.添加DataAccess對Model的引用,添加BreakAwayConsole對DataAccess和Model的引用後,在控制臺中創建一條記錄並插入數據庫,此時DbContext會自動為你創建數據庫和表。

技術分享 using DataAccess;
using Model;

namespace BreakAwayConsole
{
class Program
{
static void Main ( string [ ] args )
{
var destination = new Destination ( )
{
Country = "美國" ,
Description = "風城" ,
Name = "芝加哥"
};
using ( var context = new BreakAwayContext ( ) )
{
context.Destinations.Add ( destination );
context.SaveChanges ( );
}
}
}
} 控制臺.program

ctrl+F5運行程序,等待片刻數據庫就創建完畢了。

技術分享

字段屬性映射的默認約定

屬性與主鍵約定:Id或類名Id將默認自動映射為主鍵。

屬性與字符約定:字符類型的屬性默認自動映射為nvarchar(max) null。

屬性與bool約定:布爾值類型的屬性默認自動映射為bit

屬性與byte數組約定:byte數組類型的屬性默認自動映射為varbinary ( max)

集合屬性與主外鍵約定:泛型集合中的類會被視為外鍵表,外鍵表總是有一個外鍵引用了當前具有泛型集合的類,外鍵可以是一個int也可以直接是它所引用的類類型。如下:

public int DestinationId { get; set; }
public Destination Destination { get; set; }

配置實體字段屬性

有兩種方式可為字段增加描述性配置,Data Annotations和Fluent API,前者使用簡單,後者提供更強大的清潔的配置。(如果不喜歡到處貼標簽)

1.Data Annotations配置(System.ComponentModel.DataAnnotations)

技術分享 [Table ( "Animal" )]
//將類映射為Animal表
[Key]
//主鍵,且種子增量每次+1,即自動增長,增量為1
[Key, DatabaseGenerated ( System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity )]
//如果主鍵類型是Guid,則必須配置此特性,否則不會自動生成唯一標識
[Required]
//不允許空值
[MaxLength ( 255 )]
//最大長度
[MinLength ( 10 )]
//最小長度
[Timestamp]
//並發時間戳,為開放式並發環境配置時間戳。一個實體只能有一個byte [ ] 類型的屬性可設置此特性,Sql Server稱其為TimeStamp(時間戳),其他數據庫稱其為RowVersion(行版本)
[ConcurrencyCheck]
//並發非時間戳,當並發沖突發生時,這將為並發提供檢查確保不會發生異常。對應的字段類似:public int SocialSecurityNumber { get; set; } 配置實體字段屬性

2.Fluent API配置 (System.Data.Entity.ModelConfiguration和System.Data.Entity)

System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<T>泛型類用以配置實體的屬性,將其映射為數據庫表字段的特性。為此,你應該創建一個表示為實體類增加配置的類,接著通過在構造函數中初始化這些配置信息。然後重寫DbContext的OnModelCreating()方法,該方法會在創建表之前將配置信息應用到數據庫,所以將每一個實體類的配置信息註冊在modelBuilder.Configurations集合中即可。 技術分享 ToTable ( tableNameString)
//設置映射為數據庫的表名
HasKey ( lambda)
//主鍵,且種子增量每次+1,即自動增長,增量為1
HasPrecision ( n1, n2)
//為decimal類型的屬性保留有效位數和小數位數,n1為有效位數,n2為小數位數
Property ( lambda).HasDatabaseGeneratedOption ( System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity )
//如果主鍵類型是Guid,則必須配置此項,否則不會自動生成唯一標識
Property ( lambda).IsRequired ( )
//允許空
Property ( lambda).HasMaxLength ( )
//字符長度
Property ( lambda).HasColumnType ( "image" )
//列類型為二進制圖像數據
Property ( lambda).IsRowVersion ( )
//並發時間戳,為開放式並發環境配置時間戳。一個實體只能有一個byte [ ] 類型的屬性可設置此特性,Sql Server稱其為TimeStamp(時間戳),其他數據庫稱其為RowVersion(行版本)
Property ( lambda).IsConcurrencyToken ( )
//並發非時間戳,當並發沖突發生時,這將為並發提供檢查,確保不會發生異常。對應的屬性字段的類型為int 配置實體字段屬性 技術分享 using System.Data.Entity.ModelConfiguration;
using System.Data.Entity;
using Model;

namespace DataAcess
{
//Destination表的列配置
public class DestinationConfiguration : EntityTypeConfiguration<Destination>
{
public DestinationConfiguration ( )
{
ToTable ( "Destination" );
HasKey ( d => d.DestinationId );
Property ( d => d.Name ).HasMaxLength ( 255 ).IsRequired();
Property ( d => d.Description ).HasMaxLength ( 255 ).IsRequired ( );
Property ( d => d.Photo ).HasColumnType ( "image" );
}
}

//Lodging表的列配置
public class LodgingConfiguration : EntityTypeConfiguration<Lodging>
{
public LodgingConfiguration ( )
{
//……
}
}
public class BreakAwayContext : DbContext
{
//使用此靜態構造函數指定數據庫的初始化方式,無論如何請先關閉數據庫,否則以下任務不會完成
static BreakAwayContext ( )
{
Database.SetInitializer ( new CreateDatabaseIfNotExists<BreakAwayContext> ( ) ); //默認,參數可為null,當數據庫不存在時,自動創建數據庫
Database.SetInitializer ( new DropCreateDatabaseAlways<BreakAwayContext> ( ) ); //無論怎樣,刪除同名數據庫,再重新創建
Database.SetInitializer ( new DropCreateDatabaseIfModelChanges<BreakAwayContext> ( ) ); //如果實體模型發生改變,則先刪除同名數據庫,再重新創建
}

public BreakAwayContext ( ) : base ( "name=DBConnection" ) { } //name=配置文件中的數據庫連接字符串的名稱
public DbSet<Destination> Destinations { get; set; } //你創建的實體類Destination,實體代表了一張表,此處通過DbSet泛型集合表示該表的所有記錄
public DbSet<Lodging> Lodgings { get; set; } //你創建的實體類Lodging,實體代表了一張表,此處通過DbSet泛型集合表示該表的所有記錄

//實體被映射為表之前OnModelCreating會被運行,這將進行列配置檢查並應用列配置
protected override void OnModelCreating ( DbModelBuilder modelBuilder )
{
modelBuilder.Configurations.Add ( new DestinationConfiguration ( ) ); //註冊Destination表的列配置
modelBuilder.Configurations.Add ( new LodgingConfiguration ( ) ); //註冊Lodging表的列配置
}
}
} 示例

實體關系的默認約定

假設有X和Y兩個類。

技術分享 //一對一:兩個類分別包含對方的一個引用
namespace Model
{
public class X
{
public int XId { get; set; } //主鍵
public Y y { get; set; } //引用Y
}

public class Y
{
public int YId { get; set; } //主鍵
public X x { get; set; } //引用X
}
} 一對一 技術分享 // 一對多:兩個類中分別包含一個集合屬性和一個引用
namespace Model
{
public class X
{
public int XId { get; set; } //主鍵
public List<Y> Ys { get; set; } //一對多,一個X對多個Y
}

public class Y
{
public int YId { get; set; } //主鍵
public X x { get; set; } // 作為外鍵引用X
}
} 一對多 技術分享 //多對多:兩個類分別包含對方的一個集合屬性
namespace Model
{
public class X
{
public int XId { get; set; } //主鍵
public List<Y> Ys { get; set; }
}

public class Y
{
public int YId { get; set; } //主鍵
public List<X> Xs { get; set; }
}
} 多對多

配置實體關系

技術分享 HasRequired ( lambdaForForeignKey )
//設置當前表的哪個字段為必須的外鍵,該字段不可以為null
HasOptional( lambdaForForeignKey )
//設置當前表的哪個字段為不必須的外鍵,該字段可以為null
//示例:
//通常情況下應在外鍵表寫關系
HasRequired ( b => b.User );//當前表的哪個字段作為必須的外鍵並且是不可以為null的
HasOptional ( b => b.User ); //當前表的哪個字段作為不必須的外鍵並且是可以為null的
HasRequired ( b => b.User ).WithMany ( ); //當前表的哪個字段作為必須的外鍵並且是不可以為null的(HasRequired),該外鍵表對主鍵表的引用也可以是多個外鍵引用同一個主鍵(WithMany) 配置實體關系

示例

技術分享 //Lodging表的列配置
public class LodgingConfiguration : EntityTypeConfiguration<Lodging>
{
public LodgingConfiguration ( )
{
HasRequired ( l=>l.Destination ); //外鍵不可以為null
Property ( l=>l.Name ).HasMaxLength ( 20 ).IsRequired ( ); //可空字段
}
} 示例

.NET - EntityFramework 實體關系數據模型