第二章(6)跨多表拆分一个实体
问题:
你现在有两张以上的表,他们共享了同一个主键,然后你想一个实体映射到这两张表中。
解决过程:
让我们把问题勾画成图2-6-1这张表:
图2-6-1
接着,要建立一个代表这两张表的模型,按如下步骤:
- 在你的项目上右键,添加一个新的模型。选择“添加”->"添加新项"。选择ADO.NET 实体数据模型。
- 选择“从数据库中生成”,点击“下一步”。
- 使用向导选择一个已有数据库连接,或者新建一个。
- 在弹出的“选择数据库对象”框中,选择Product和ProductWebInfo表,保持最下面的两个复选框选中。
生成的模型如图2-6-2所示:
图2-6-2
既然我们已经把两张表导入了模型,现在我们要做的事就是把两个实体合成一个实体。步骤如下:
- 把ProductWebInfo实体中的ImageURL标量属性复制到Product实体中。你可以用复制/粘贴,但不用复制SKU标量属性。
- 在ProductWebInfo实体上右键,选择“删除”。如图2-6-3,它提示是否要删除数据库中表,选择“否”。这保证存储层的模型不会被删除。
- 点击Product实体,查看映射细节窗口。如果映射细节窗口没有显示的,在菜单栏中选择View-》other windows-》entity data Model Mapping Details.
- 在Product实体的映射细节窗口,点击“添加表或视图”,选择ProductWebInfo表。这就把ProductWebInfo表添加到Product实体的映射中了。
- 在映射细节窗口的ProductWebInfo表下,把ImageURL列和ImageURL属性映射起来。同时保证SKU属性是和ProductWebInfo表中的SKU列对应的。最后的映射如图2-6-4所示。
图2-6-3
图2-6-4
原因:
在传统的系统中,每一行的额外信息要在另外一张表中找到的情况非常常见。通常发生在数据库演变和添加列一些关键的表但不愿意打破现有的代码的情况。解决的办法就是把额外的信息保存在一张新表中。
通过合并两个或更多表到一个单一的实体,将一个单一的实体跨两个或更多表,我们可以把所有的部件作为一个逻辑实体。这个过程通常被称为垂直分割。
垂直分割不利的一面是,我们每次要获得这个实体实例的时候都需要通过额外连接来保证实体类型完整。
SELECT
[Extent1].[SKU] AS [SKU],
[Extent2].[Description] AS [Description],
[Extent2].[Price] AS [Price],
[Extent1].[ImageURL] AS [ImageURL]
FROM [dbo].[ProductWebInfo] AS [Extent1]
INNER JOIN [dbo].[Product] AS [Extent2] ON [Extent1].[SKU] = [Extent2].[SKU]
using (var context = new EFRecipesEntities()) { var product = new Product { SKU = 147, Description = "Expandable Hydration Pack", Price = 19.97M, ImageURL = "/pack147.jpg" }; context.Products.AddObject(product); product = new Product { SKU = 178, Description = "Rugged Ranger Duffel Bag", Price = 39.97M, ImageURL = "/pack178.jpg" }; context.Products.AddObject(product); product = new Product { SKU = 186, Description = "Range Field Pack", Price = 98.97M, ImageURL = "/noimage.jp" }; context.Products.AddObject(product); product = new Product { SKU = 202, Description = "Small Deployment Back Pack", Price = 29.97M, ImageURL = "/pack202.jpg" }; context.Products.AddObject(product); context.SaveChanges(); } using (var context = new EFRecipesEntities()) { foreach (var p in context.Products) { Console.WriteLine("{0} {1} {2} {3}", p.SKU, p.Description, p.Price.ToString("C"), p.ImageURL); } }
output
------------------------------------- 147 Expandable Hydration Pack $19.97 /pack147.jpg 178 Rugged Ranger Duffel Bag $39.97 /pack178.jpg 186 Range Field Pack $98.97 /noimage.jpg 202 Small Deployment Back Pack $29.97 /pack202.jpg -------------------------------------