第二章(7)跨多实体拆分一张表
问题:
一张表中,有一些字段频繁被使用,而有几个大字段是几乎没被使用过。为了性能考虑,你想避免每次查询的时候都加载这些“消耗昂贵”的字段。这样就需要把一张表分割成两个及以上的实体。
解决过程:
假设你有这样一张表,如图2-7-1所示。这张表持有照片的信息,同时包括bit级的缩略图和全分辨率的图像。
图2-7-1
创建频繁使用字段的实体和包含很少使用的字段实体的步骤如下:
- 在工程项目上右键,选择添加“新项”,选择ADO.NET实体数据模型。
- 选择“从数据库中生成”,点击“下一步”。
- 使用向导选择一个已有数据库连接,或者新建一个。
- 在弹出的“选择数据库对象”框中,选择Photograph表,保持最下面的两个复选框选中。点击“完成”。
- 在设计界面上右键,选择添加“实体”。在弹出的对话框中,将实体的名字改为“PhotographFullImage”,同时把主键的名字改成PhotoId,这和Photograph实体中的主键名是一样。如图2-7-2所示,点击完成添加新的PhotographFullImage实体类型。
- 将HighResolutionBits属性从Photograph实体类型中移到PhotographFullImage实体中。你可以用选择/剪切/粘贴来移动属性。
- 点击新创建的PhotographFullImage实体查看它的映射细节。如果映射细节的窗口不可见,在菜单中选择视图-》其他窗口-》实体数据模型映射细节。
- 在PhotographFullImage的映射细节窗口,点击添加表或者视图,然后选择Photograph表。将HighResolutionBits列和HighResolutionBIts属性,PhotoId列和PhotoId属性对应起来。如图2-7-3.
- 在Photograph实体中右键,选择添加关联(Association)。添加Photograph实体和PhotographFullImage实体之间的一对一关联。确保两件事情:在关联的两个终端的多样性选择了1 和取消选中“添加外键属性”复选框。如图2-7-4.
- 在关联上右键,选择“属性”。在约束区域底部的引用约束中,点击按钮添加一个引用约束。将Photograph设为主实体,同时确保主实体和依赖实体的主键属性都设为了PhotoId。如图2-7-5.
图2-7-2
图2-7-3
图2-7-4
图2-7-5
这样完成的模型如图2-7-6所示:
图2-7-6
原因:
Entity Framework并不直接支持单独实体属性的延迟加载的概念。为了得到延迟加载昂贵属性的效果,我们利用了EF支持关联实体延迟加载的功能。也就是创建一个新的实体类型来保存昂贵的全图像属性,然后创建一对一的实体关联。并且在概念层中添加了引用约束,有点像数据库中的引用约束,告诉EF实体PhotographFullImage不能没有Photograph而单独存在。
也因为引用约束,在我们的模型中有些东西是要注意的。如果我们新建了一个PhotographFullImage实体,那么一个Photograph的实例必须要存在于object context中,或者数据源先调用了savechanges方法。同样,如果我们删除了一个Photograph,那么与之关联的PhotographFullImage也要被删除。这就像数据库中引用约束的级联删除。
byte[] thumbBits = new byte[100]; byte[] fullBits = new byte[2000]; using (var context = new EFRecipesEntities()) { var photo = new Photograph { PhotoId = 1, Title = "My Dog", ThumbnailBits = thumbBits }; var fullImage = new PhotographFullImage { PhotoId = 1, HighResolutionBits = fullBits }; photo.PhotographFullImage = fullImage; context.Photographs.AddObject(photo); context.SaveChanges(); } using (var context = new EFRecipesEntities()) { foreach (var photo in context.Photographs) { Console.WriteLine("Photo: {0}, ThumbnailSize {1} bytes", photo.Title, photo.ThumbnailBits.Length.ToString()); // explicitly load the "expensive" entity, PhotographFullImage photo.PhotographFullImageReference.Load(); Console.WriteLine("Full Image Size: {0} bytes", photo.PhotographFullImage.HighResolutionBits.Length.ToString()); } }
-------------------------------------------------- Photo: My Dog, Thumbnail Size: 100 bytes Full Image Size: 2000 bytes --------------------------------------------------