本主题演示如何使用 Entity Framework Designer(EF Designer)映射复杂类型,以及如何查询包含复杂类型的属性的实体。
下图显示了使用 EF 设计器时使用的主窗口。
注释
生成概念模型时,错误列表中可能会显示有关未映射实体和关联的警告。 可以忽略这些警告,因为在选择从模型生成数据库后,这些错误将消失。
什么是复杂类型
复杂类型是实体类型的非标量属性,允许在实体内组织标量属性。 与实体一样,复杂类型包括标量属性或其他复杂类型属性。
处理表示复杂类型的对象时,请注意以下事项:
- 复杂类型没有键,因此不能独立存在。 复杂类型只能作为实体类型或其他复杂类型的属性存在。
- 复杂类型不能参与关联,并且不能包含导航属性。
- 复杂类型属性不能为 null。 调用 DbContext.SaveChanges 并遇到 null 复杂对象时,将发生 **InvalidOperationException **。 复杂对象的标量属性可以为 null。
- 复杂类型无法继承自其他复杂类型。
- 必须将复杂类型定义为 类。
- 调用 DbContext.DetectChanges 时,EF 会检测对复杂类型对象上成员的更改。 实体框架在调用以下成员时自动调用 DetectChanges : DbSet.Find、 DbSet.Local、 DbSet.Remove、 DbSet.Add、 DbSet.Attach、 DbContext.SaveChanges、 DbContext.GetValidationErrors、 DbContext.Entry、 DbChangeTracker.Entries。
将实体的属性重构为新的复杂类型
如果概念模型中已有实体,可能需要将某些属性重构为复杂类型属性。
在设计器图面上,选择实体的一个或多个属性(不包括导航属性),然后右键单击并选择“ 重构 -> 移动到新复杂类型”。
将具有所选属性的新复杂类型添加到 模型浏览器。 为复杂类型提供默认名称。
新创建类型的复杂属性将替换所选属性。 保留所有属性映射。
创建新的复杂类型
还可以创建不包含现有实体属性的新复杂类型。
在模型浏览器中右键单击 复杂类型 文件夹,指向 添加新的复杂类型...。 或者,可以选择 “复杂类型” 文件夹,然后按键盘上的 “插入 ”键。
将新的复杂类型添加到具有默认名称的文件夹。 现在可以向类型添加属性。
向复杂类型添加属性
复杂类型的属性可以是标量类型或现有复杂类型。 但是,复杂类型属性不能有循环引用。 例如,复杂类型 OnsiteCourseDetails 不能具有复杂类型 OnsiteCourseDetails 的属性。
可以通过下面列出的任何方式将属性添加到复杂类型。
在模型浏览器中右键单击复杂类型,指向 “添加”,然后指向 Scalar 属性 或 复杂属性,然后选择所需的属性类型。 或者,可以选择复杂类型,然后按键盘上的 Insert 键。
新属性将添加到具有默认名称的复杂类型。
或-
右键单击 EF 设计器 图面上的实体属性并选择“ 复制”,然后右键单击 模型浏览器中 的复杂类型,然后选择“ 粘贴”。
重命名复杂类型
重命名复杂类型时,所有对该类型的引用都会在整个项目中更新。
在 模型浏览器中慢慢双击复杂类型。 名称将被选中并处于编辑模式。
或-
在 模型浏览器中 右键单击复杂类型,然后选择“ 重命名”。
或-
在模型浏览器中选择复杂类型,然后按 F2 键。
或-
在 模型浏览器中 右键单击复杂类型,然后选择 “属性”。 在 “属性” 窗口中编辑名称。
将现有复杂类型添加到实体,并将其属性映射到表列
右键单击实体,指向“ 添加新”,然后选择“ 复杂属性”。 具有默认名称的复杂类型属性将添加到实体。 将默认类型(从现有复杂类型中选择)分配给该属性。
请在“属性”窗口中为属性分配所需类型。 将复杂类型属性添加到实体后,必须将其属性映射到表列。
右键单击设计图面或 模型浏览器中 的实体类型,然后选择 “表映射”。 表映射显示在 “映射详细信息” 窗口中。
展开 映射到 <表名>节点。 此时会显示 列映射 节点。
展开 列映射 节点。 此时会显示表中所有列的列表。 用于列的映射的默认属性(如果有)列在值/属性标题下。
选择要映射的列,然后右键单击相应的 值/属性 字段。 将显示所有标量属性的下拉列表。
选择适当的属性。
对每个表列重复步骤 6 和 7。
注释
若要删除列映射,请选择要映射的列,然后单击 “值/属性 ”字段。 然后,从下拉列表中选择 “删除 ”。
将函数导入映射到复杂类型
函数导入基于存储过程。 若要将函数导入映射到复杂类型,相应存储过程返回的列必须与数字中的复杂类型的属性匹配,并且必须具有与属性类型兼容的存储类型。
双击您要映射到复杂类型的导入函数。
填写新函数导入的设置,如下所示:
指定要在 “存储过程名称 ”字段中创建函数导入的存储过程。 此字段是一个下拉列表,用于显示存储模型中的所有存储过程。
在 “函数导入名称 ”字段中指定函数导入的名称。
选择 “复杂 ”作为返回类型,然后通过从下拉列表中选择适当的类型来指定特定的复杂返回类型。
单击 “确定” 。 函数导入条目是在概念模型中创建的。
自定义函数导入时的列映射
- 右键单击模型浏览器中的函数导入,然后选择 “函数导入映射”。 此时会显示 “映射详细信息 ”窗口,并显示函数导入的默认映射。 箭头指示列值和属性值之间的映射。 默认情况下,假定列名与复杂类型的属性名称相同。 默认列名以灰色文本显示。
- 如有必要,请更改列名以匹配与函数导入相对应的存储过程返回的列名。
删除复杂类型
删除复杂类型时,将从概念模型中删除该类型,并删除该类型的所有实例的映射。 但是,针对这种类型的引用不会被更新。 例如,如果实体具有 ComplexType1 类型的复杂类型属性,并且 Model Browser 中删除了 ComplexType1,则不会更新相应的实体属性。 模型不会验证,因为它包含引用已删除的复杂类型的实体。 可以使用实体设计器更新或删除对已删除复杂类型的引用。
在模型浏览器中右键单击复杂类型,然后选择“ 删除”。
或-
在模型浏览器中选择复杂类型,然后按键盘上的 Delete 键。
查询包含复杂类型的属性的实体
以下代码演示如何执行返回包含复杂类型属性的实体类型对象的集合的查询。
using (SchoolEntities context = new SchoolEntities())
{
var courses =
from c in context.OnsiteCourses
order by c.Details.Time
select c;
foreach (var c in courses)
{
Console.WriteLine("Time: " + c.Details.Time);
Console.WriteLine("Days: " + c.Details.Days);
Console.WriteLine("Location: " + c.Details.Location);
}
}