Entity Framework In Action--5 Domain model mapping(1)

 5.1 The Entity Data Model

  EDM是EF的心脏。本质上来说,EF是一个工具,他通过创建一个介于对象模型和数据库的抽象层来为他们解耦和。你已经知道EDM被分为了三个部分:

  概念模型(CSDL)--描述对象模型。在这部分类和他们的关系有他们的副本。

  存储模型(SSDL)--描述数据库结构。表、视图,甚至存储过程和函数会在这个部分。

  映射模型(MSL)--映射CSDL和SSDL。

  5.1.1 The Entity Data Model and Visual Studio designer

  双击Solution Explorer里的EDMX文件,VS打开设计器,显示实体。右键单击EDMX,选择“Open With..”,选择"XML(Text)Editor"。

  

      

  EDM在edmx:Edmx/edmx:Runtime路径下。在他里面,你可以看到存储(storage)、概念(conceptual)和映射模型。

  EF不是对所有的EDMX文件感兴趣--它甚至不能解析他。EF仅仅知道被分为三部分的映射文件:csdl、ssdl、msl。

  EDMX文件包含EDM,但是EF不知道他。

   

    5.2 Creating consumable entities

  1、创建实体代码。

  2、创建概念模型。

  3、创建存储模型。

  4、创建映射模型。

  5.2.1 Writing the entities

public class AddressInfo
{
  public virtual string Address { get; set; }
  Public virtual string ZipCode { get; set; }
  Public virtual string City { get; set; }
  Public virtual string Country { get; set; }
}
public class Order
{
  public virtual int OrderId { get; set; }
  public virtual DateTime OrderDate { get; set; }
  public virtual AddressInfo ShippingAddress { get; set; }
  public virtual DateTime EstimatedShippingDate { get; set; }
  public virtual DateTime ActualShippingDate { get; set; }
}
public class OrderDetail
{
  public virtual int OrderDetailId { get; set; }
  public virtual int Quantity { get; set; }
  public virtual decimal Price { get; set; }
  public virtual decimal Discount { get; set; }
}

  当你实例化(instantiate)Order时,因为没有被创建address是null。这意味着在你创建Order的时候要创建address,那是容易重复出错的地方。你有两个选择解决这个问题:在Order构造函数内实例化address,或者在它第一次被访问的时候实例化他。  

public Order()
{
  ShippingAddress = new AddressInfo();
}

private AddressInfo _ShippingAddress; public virtual AddressInfo ShippingAddress {   get     {       _ShippingAddress = _ShippingAddress ?? new AddressInfo();       return _ShippingAddress;     }   set     {       _ShippingAddress = value;     } }

  Equals和GetHashCode的重写。当你创建一个对象,为每个类实现他们很重要。

public class Order
{
  ...
  public override bool Equals(object obj)
  {
    Order order = obj as Order;
    if (order == null) return false
    return order.OrderId == this.OrderId;
  }
  
public override int GetHashCode()   {     return OrderId.GetHashCode();   } }

   这段代码说的是如果两个order的OrderId属性相同,他们相等。

  一个类必须能被继承而且所有属性必须是virtual/Overridable。你可以避免这样的规则,但是被获取的对象不会提供像对象追踪和延迟加载等特性。因为在很多情况下他们是很重要的,我们建议将属性设为virtual。   

  5.2.2 Describing entities in the conceptual schema.

  概念模型(conceptual schema)包括对实体的描述。

  在OrderIT的EDMX文件里,概念模型的路径是 edmx:Edmx/ edmx:Runtime/edmx:ConceptualModels.如果你手动创建概念文件,你可以为他起名OrderIT.csdl并在数据库连接字符串引用他。

  基本的csdl结构是相当简单的。他有主元素Schema,在他内部是一个EntityContainer元素,加上每个实体一个的EntityType和每个复杂类型的一个ComplexType。

  Schema

  Schema是一个很简单的元素。他包含了Namespace属性和Alias来区分命名空间并给他一个别名(alias)。除此之外,他通过xmlns声明了基础命名空间,并添加prefix前缀声明一个额外的命名空间。  

<Schema xmlns="http://schemas.microsoft.com/ado/2008/09/edm"
     xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/" 
     Namespace
="OrderITModel"
     Alias
="Self"> ... </Schema>

  因为Schema不过(mere)是一个容器,他没有太多特别的属性。我们更感兴趣的是他的内容。

  EntityContainer

  EntityContainer元素声明了EDM里的实体集合关系集。这里声明的实体集用来生成上下文类的代码。这个元素只有Name属性,这个name就是设计器你在EDMX向导输入的连接字符串的名字。如果你手动的创建文件,我们建议你设定name为你的程序名,再加上后缀Entities。

    

注意:你可能有很多的EntityContainer标签,意味着你有很多的上下文。这在你想要有逻辑地区分你的应用的时候会很有用。设计器不支持

它,但是你可以手动编辑它。

  正如你所料的(As you may expect),EntityContainer只是一个外包。在他里面是每一个实体集的EntitySet元素。你在第2章学到在模型(model)里,对于每个类都有一个实体集,不继承于另一个。例如,Order有一个实体集,Company有一个实体集,但是因为Supplier和Customer继承自Company,所以他们没有实体集。

  EntitySet有两个属性:

  Name声明实体集的唯一名字。

  EntityType 包含实体公开的完全名称(fully qualified name,FQN)。

  最后,实体容器看起来是下面这样的:  

<EntityContainer Name="OrderITEntities">
  <EntitySet Name="Orders" EntityType="OrderIT.DomainModel.Order" />
  <EntitySet Name="OrderDetails"EntityType="OrderITModel.OrderDetail" />
</EntityContainer>


  
ComplexType And EntityType  

  现在你明白了EntityContainer,我们可以去看看模型类了。用来描述一个实体的元素是EntityType,而一个复杂类型用ComplexType来表示。

  ComplexType只有Name属性,填入类的完全名称。在他内部为每个属性提供一个名为Property的节点。Property有很多属性,看下表:

Attribute   Description Required
Name   识别属性的名称 Yes  
Type 识别属性的CLR类型,如果属性是复杂类型,这里是属性的完全名称。  Yes
Nullable    是否属性值可以为null,默认是true No
FixedLength 属性是不是固定长度的 No
MaxLength 值的最大长度 No
Scale 在一个decimal类型里,逗号(comma)后面有多少位 No
Precision   decimal有多少位 No
store:StoreGeneratedPattern

在插入和更新的时候,列是如何被数据库设置的,三个可能的值:

  None-从应用程序来的值被用。

  Identity-插入的时候被数据库计算,更新的时候用应用程序的值。

  Computed-在插入和更新的时候都被数据库计算。

No
ConcurrencyMode(并发模式) 属性是否做并发检查,执行检查,设置值为Fixed No

  当复杂类型准备好的时候,你就可以用它来创建实体了。EntityType是你做这个的地方。他有一个强制性(mandatory)的Name属性,类的名称被指定的。他有两个选择属性:

  Abstract-是不是抽象类。

  BaseType-是不是基类。

   当继承起作用的时候,Abstract和BaseType就变的重要了。在EntityType里,每个scalar和复杂属性都有一个Property元素,和一个Key元素来识别主键。如果属性是复杂类型,设定Type属性为完全名称。Key元素没有属性,他有一个PropertyRef节点来表示主键。PropertyRef只有Name属性。   

<ComplexType Name="AddressInfo">
  <Property Type="String" Name="Address" Nullable="false" MaxLength="50" />
  <Property Type="String" Name="City" Nullable="false" MaxLength="50" />
  <Property Type="String" Name="ZipCode" Nullable="false" MaxLength="15" />
  <Property Type="String" Name="Country" Nullable="false" MaxLength="30" />
</ComplexType>
<EntityType Name="Order">
  <Key>
    <PropertyRef Name="OrderId" />
  </Key>
  <Property Type="Int32" Name="OrderId" Nullable="false" store:StoreGeneratedPattern="Identity" />
  <Property Name="ShippingAddress" Type="OrderITModel.AddressInfo" Nullable="false" />
  <Property Type="DateTime" Name="EstimatedShippingDate" Nullable="false" Precision="29" />
  <Property Type="DateTime" Name="ActualShippingDate" Nullable="false" Precision="29" />
</EntityType>
<EntityType Name="OrderDetail">
  <Key>
    <PropertyRef Name=" OrderDetail Id" />
  </Key>
  <Property Type="Int32" Name="OrderDetailId" Nullable="false" store:StoreGeneratedPattern="Identity" />
  <Property Type="Int16" Name="Quantity" Nullable="false" />
  <Property Type="Decimal" Name="UnitPrice" Nullable="false" Precision="29" Scale="29" />
  <Property Type="Decimal" Name="Discount" Nullable="false" Precision="29" Scale="29" />
</EntityType>

  

  

 

  

  

posted @ 2013-07-11 12:00  小飞的DD  阅读(259)  评论(0编辑  收藏  举报