Table Splitting
前言
資料庫的欄位只要一多,未經調整的情況下使用Entity Framework將資料撈回來,會把全部的欄位都撈回來,可是實際上某些情況,你常常用的到欄位就只有一些而已,並不是全部都會用到。 這種多拉回來的資料也是一種浪費,而Entity Framework 可以使用Table Splitting的方式來解決這個問題,Table Splitting允許兩個POCO class對應到資料庫的一個table,而取資料的時候只會取得一個POCO class的內容。
我們Person Table為例,假設我們實際上比較會用到Name這個欄位,而Image,Caption比較少用到。
而且做的則是將Person拆成兩個POCO class,Perosn與PersonPhoto,且使用Data Annotation指向同一個table name ,如下:
[Table("Person")]
public class Person
{
[Key]
public int PersonId { get; set; }
public string Name { get; set; }
public PersonPhoto Photo { get; set; }
}
[Table("Person")]
public class PersonPhoto
{
[Key]
public int PersonId { get; set; }
public byte[] Image { get; set; }
public string Caption { get; set; }
public Person Person { get; set; }
}
接著使用Fluent API設定關聯
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasRequired(p => p.Photo)
.WithRequiredDependent(p => p.Person);
}
這樣就完成兩個POCO class對應到一個table的方式了。
注意,使用Table Splitting規則:
POCO class 必須要one-to-one relationshop
POCO class 必須共享同一個Key
產生的SQL
接下來我們來看,Entity Framework怎麼幫我們產生SQL
SELECT
var person = db.Person.FirstOrDefault(x => x.Name.Equals("Miles"));
SELECT TOP (1)
[Extent1].[PersonId] AS [PersonId],
[Extent1].[Name] AS [Name]
FROM [dbo].[Person] AS [Extent1]
WHERE N'Miles' = [Extent1].[Name]
使用Eager loading
var person = db.Person.Include("Photo").FirstOrDefault(x => x.Name.Equals("Miles"));
SELECT TOP (1)
[Extent1].[PersonId] AS [PersonId],
[Extent1].[Name] AS [Name],
[Extent1].[Image] AS [Image],
[Extent1].[Caption] AS [Caption]
FROM [dbo].[Person] AS [Extent1]
WHERE N'Miles' = [Extent1].[Name]
INSERT
using (var db = new Model1())
{
var p = new Person()
{
Name = "Bob",
Photo = new PersonPhoto()
};
db.Person.Add(p);
db.SaveChanges();
}
exec sp_executesql N'INSERT [dbo].[Person]([Name], [Image], [Caption])
VALUES (@0, NULL, NULL)
SELECT [PersonId]
FROM [dbo].[Person]
WHERE @@ROWCOUNT > 0 AND [PersonId] = scope_identity()',N'@0 nvarchar(max) ',@0=N'Bob'
UPDATE
using (var db = new Model1())
{
var person = db.Person.FirstOrDefault(x => x.Name.Equals("Bob"));
person.Name = "Kevin";
db.SaveChanges();
}
exec sp_executesql N'UPDATE [dbo].[Person]
SET [Name] = @0
WHERE ([PersonId] = @1)
',N'@0 nvarchar(max) ,@1 int',@0=N'Kevin',@1=2
DELETE
方法一:
using (var db = new Model1())
{
var person = db.Person.Include("Photo").SingleOrDefault(x => x.Name.Equals("Miles"));
db.PersonPhoto.Remove(person.Photo);
db.Person.Remove(person);
db.SaveChanges();
}
方法二:
using (var db = new Model1())
{
var person = db.Person.Include("Photo").SingleOrDefault(x => x.Name.Equals("Miles"));
db.Entry<PersonPhoto>(person.Photo).State = EntityState.Deleted;
db.Entry<Person>(person).State = EntityState.Deleted;
db.SaveChanges();
}
exec sp_executesql N'DELETE [dbo].[Person]
WHERE ([PersonId] = @0)',N'@0 int',@0=2
小結
Table Splitting主要是幫助我們加快搜尋的速度,實際上Delete,Update,Insert幫助沒有太大,反而要多寫code,所以至於到底要不要使用Table Splitting還是得視情況而定。
一天一分享,身體好健康。
該追究的不是過去的原因,而是現在的目的。