2014年11月19日 星期三

[Entity Framework 6] Code First (1)

.NET   Entity Framework   Code First

背景

How to implement Code first in Entity framework.

環境

l   Windows 7 pro
l   IIS Express 7.5
l   Visual Studio 2012 (C#)
l   MS Sql Server 2008 R2
l   Entity Framework 5

步驟



l   設定Web.Config的資料庫Connection String
l   建立基底欄位的類別:BaseEntity
l   實作資料表 Customers,Reservations,Rooms 設定相關屬性(Pkey, Foreign Key …)
l   建立繼承DbContext資料庫Context : HotelDbContext
l   實作第一次建立資料庫之後的Initial Load程式碼



實作


Database connection

l   設定Web.Config的資料庫Connection String

<connectionStrings>
<
add name="HotelDbContext" 
connectionString="Data Source=localhost; Initial Catalog=RoomReserve; Integrated Security=True;
MultipleActiveResultSets=True
"
providerName="System.Data.SqlClient" />
</
connectionStrings>


以連到本機的Sql Express為例。
設定的連線名稱:HotelDbContext在步驟2.會使用到。




Model (DAO)

l   BaseEntity
建立基底欄位的類別:BaseEntity 以及設定Property的預設值
public class BaseEntity
{
        ///
 <summary>
        ///
 建立日期
        
/// </summary>
        public DateTime CreateOn { get; set; }
        ///
 <summary>
        ///
 
更新日期
        
/// </summary>
        public DateTime UpdateOn { get; set; }

        public
 BaseEntity()
        {

         
CreateOn = DateTime.Now;
           UpdateOn = 
DateTime.Now;
         }
}

l   Customer

public class Customer : BaseEntity
{
   [
Key]
   [
Column(Order = 1)]
   [
Display(Name = "身分字號")]
   
public String RegId { get; set; }

   [
Column(Order = 2)]
   [
Display(Name = "姓名")]
   
public String Name {get; set;}
   
   [
Column(Order = 3)]
   [
Display(Name = "電話號碼")]
   
public String Phone { get; set; }
   
   
public virtual  ICollection<Reservation> Reservations { get; set; }  //備註
}

備註: 表示一對多關係,一個Customer可以有多筆Reservation

l   Room

public class Room : BaseEntity
{
  [
Key]
  [
Required]
  [
Column(Order=1)]
  [
Display(Name="房號")]
  
public String RoomId { get; set; }

  [
Column(Order = 2)]
  [
Display(Name = "價格")]
  
public int Price { get; set; }

  
public virtual ICollection<Reservation> Reservations { get; set; } //備註
}

備註: 表示一對多關係,一個Room可以對應到多筆Reservation

l   Reservation

public class Reservation: BaseEntity
{
  
[Key] //當欄位型別為int且設定為主索引鍵,則EF會將其自動編號(流水號)
  
 [Column(Order = 1)]
   
public int Id { get; set; }

   [
Column(Order = 2)]
   [
Display(Name = "房號")]
   
public String RoomId { get; set; }
   
   [
Column(Order = 3)]
   [
Display(Name = "身分字號")]
   
public String RegId { get; set; }
  
   [
Column(Order = 4)]
   [
Display(Name = "人數")]
   
public int People { get; set; }
  
   [
Column(Order = 5)]
   [
Display(Name = "訂房時間")]
   
public DateTime ReservationOn { get; set; }
   
   [
Column(Order = 6)]
   [
Display(Name = "入住時間")]
   
public DateTime CheckInOn { get; set; }
  
  
//備註一
   [
ForeignKey("RoomId")]
   
public virtual Room Room { get; set; }
   
//備註二
   [
ForeignKey("RegId")]
   
public virtual Customer Customer { get; set; }
}

備註一:指定RoomIdForeign Key,且Reference Room對應的表格。
備註二:指定RegIdForeign Key,且Reference Customer對應的表格。

DbContext

l   建立繼承DbContext的資料庫Context : HotelDbContext
public class HotelDbContext : DbContext
{
public HotelDbContext()
             : 
base("name=HotelDbContext")  //指定對應的Connection String名稱 
    { }
    //宣告資料模型: Customers (Customer類別組成)
    public
 DbSet<Customer> Customers { getset; }
//宣告資料模型: Reservations (Reservation類別組成)
public DbSet<Reservation> Reservations { getset; }
//宣告資料模型: Rooms (Room物件組成)
public DbSet<Room> Rooms { getset; }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    
try
    {
        ///
設定Customer 一對多 Reservations
        modelBuilder.Entity<
Customer>().HasMany(
m => m.Reservations).WithRequired(m => m.Customer);

       ///
設定Room 一對多 Reservations
       modelBuilder.Entity<
Room>().HasMany(
m => m.Reservations).WithRequired(m => m.Room);
    }
    
catch (Exception ex) { }
}
}

l   Initial Load

public class HotelDbInitial : 
   
CreateDatabaseIfNotExists<HotelDbContext>
{
        
protected override void Seed(HotelDbContext context)
        {

         
try
            
{
                context.Rooms.Add(
new Room() { RoomId = "100", Price = 10000 });
                context.Rooms.Add(
new Room() { RoomId = "101", Price = 9999 });
                context.Rooms.Add(
new Room() { RoomId = "102", Price = 9998 });

                 context.Customers.Add(
new Customer() { 
                    RegId=
"R22222222", 
                    Name = 
"JB", 
                    Phone = 
"09331111111" });
                 context.Customers.Add(
new Customer() { 
                     RegId=
"A22222222", 
                     Name = 
"Lily", 
                     Phone = 
"0911111111" });
                 context.SaveChanges();
            }
            
catch (Exception ex) { }
         }
}


然後在Global.asax 裡面的  Application_Start() 加入以下程式碼,即可在建立資料庫後做Initial Load

protected void Application_Start()
{
     //…
     //
註冊資料庫Initial
    
Database.SetInitializer(new HotelDbInitial());
}


備註

l   手動指定Table Name
如果我們要手動指定,只要在Model 加上以下attribute … 
[Table("MyRoom")]
public class Room : BaseEntity
{ … }

資料庫裡面的表格名稱就會建立成 MyRoom
建議同時一起修改資料庫Contex裡面的資料模型名稱:

//宣告資料模型: MyRoom (Room物件組成)
public DbSet<Room> Rooms { get; set; }     原來是設定成預設名稱 Rooms
public DbSet<Room> MyRoom { get; set; } 

這樣在程式裡面操作資料模型時,才不會因為名稱和資料庫表格名稱不同,而造成混淆。


l   宣告Property 在資料庫中為Identity欄位

[Key]
[Column(Order = 1)]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }

如果是Int (int , Int32 …)欄位且指定為Primary key,則EF會自動將其設置為Identity

l   指定Model欄位在資料庫的型態

[Required]
[Column(TypeName = "NVARCHAR")]
[MaxLength(100)]
public String Name { get; set; }


l   EF Code First中定義資料模型的欄位常用Attribute



延伸閱讀



沒有留言:

張貼留言