Entity Framework 4 in Action读书笔记——第五章:域模型映射(Domain model mapping)(二)…

Entity Framework 4 in Action读书笔记——第五章:域模型映射(Domain model mapping)(二)…

在模型中定义关系

在OrderIT模型中,有三种类型的关联:one-to-one,one-to-many和many-to-many。

One-to-one 关系

one-to-one关系的典型例子是订单详细(order detail)和订单(order)。创建这种类型的关联一点也不困难,但是涉及几个步骤:

1. 通过添加导航属性修改OrderDetail类。如果选择外键关联,还必须加上外键属性。
2. 修改CSDL将属性添加到类描述并引入关系。
3. 修改存储模式(storage schema)引入表之间的外键(如果存在)。
4. 修改映射模式(mapping schema)映射关系(只对独立关联)。

下面让我们看一下每个步骤。

修改类

创建从order detail到order的引用,需要在OrderDetail类中创建一个Order属性。因为使用了外键,还必须添加一个外键属性,如下面的清单所示:

创建order detail引用order的属性
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; }

    //导航属性
    public virtual Order Order { get; set; }
    //外键属性
    public virtual int OrderId { get; set; }
}

在代码中的工作就这些。

修改概念模式(conceptual schema)

导航属性使用NavigationProperty元素添加到Name为OrderDetail的EntityType节点。Name特性映射元素为对象中属性,Relationship需要关系的完整名称,FromRole指定起点,ToRole指定结束点。外键属性使用Property。(书中有误)

在CSDL中为实体添加导航和外键属性
        <EntityType Name="OrderDetail">
          <Property Name="OrderId" Type="Int32" Nullable="false" />
          <NavigationProperty Name="Order" Relationship="OrderITModel.FK_OrderDetail_Order" FromRole="OrderDetail" ToRole="Order" />
        </EntityType>

对实体的描述就这些。下面看一下关系描述。

在EntityContainer元素中,需要为每一个关联声明AssociationSet。它有两个特性:

  1. Name——关系集的名称。
  2. Association——指定类型。

在AssociationSet内,插入两个End节点,Role特性的值为类的名称,EntitySet的值为实体集的名称。

在EntityContainer外部,需要使用Association元素描述关系。它的Name属性链接到AssociationSet的描述,而内嵌的End元素描述关系的类型和它们的基数。在End元素中重要的就是Multiplicity特性,它有下面可选值:

1
0..1
*

End允许指定删除级联行为。这与数据库无关,只是父实体标记为删除时,子实体也被标记了。

声明和定义关联
        <EntityContainer Name="OrderITEntities" annotation:LazyLoadingEnabled="true">
          <AssociationSet Name="FK_OrderDetail_Order" Association="OrderITModel.FK_OrderDetail_Order">
            <End Role="Order" EntitySet="Orders" />
            <End Role="OrderDetail" EntitySet="OrderDetails" />
          </AssociationSet>
        </EntityContainer>
        <Association Name="FK_OrderDetail_Order">
          <End Role="Order" Type="OrderITModel.Order" Multiplicity="1">
            <OnDelete Action="Cascade" />
          </End>
          <End Role="OrderDetail" Type="OrderITModel.OrderDetail" Multiplicity="*" />
        </Association>

在本例中,Order是为1的一方,OrderDetail是为*的一方,也就是说映射的是one-to-many关系!one-to-many关系也隐式声明了one-to-one关系。一个订单有多个详细,但是一个详细只对应一个订单。

独立关联(independent association)在MSL中映射,但是外键关联(foreign-key association)在CSDL中映射。因为在本例中已经选择了外键关联,必须将映射信息添加到关联定义中。这个信息添加到Association元素内的ReferentialConstraint节点,在End节点后面。

定义外键关联
        <Association Name="FK_OrderDetail_Order">
          <End Role="Order" Type="OrderITModel.Order" Multiplicity="1">
            <OnDelete Action="Cascade" />
          </End>
          <End Role="OrderDetail" Type="OrderITModel.OrderDetail" Multiplicity="*" />
          <ReferentialConstraint>
            <Principal Role="Order">
              <PropertyRef Name="OrderId" />
            </Principal>
            <Dependent Role="OrderDetail">
              <PropertyRef Name="OrderId" />
            </Dependent>
          </ReferentialConstraint>
        </Association>

ReferentialConstraint仅仅是个容器元素。映射真正发生在Principal和Dependent节点,在这里面可以定义主类(master class)的主键和在从类(child class)的外键属性。

概念模式完成了,下面修改存储模式。

修改存储模式(storage schema)

在存储模式中描述关系和概念模式中类似。在实体容器(entity container)中声明关系,然后在它外边描述。

直接看代码吧。

在存储模式中定义数据库外键约束
     <EntityContainer Name="OrderITModelStoreContainer">
       <AssociationSet Name="FK_OrderDetail_Order" Association="OrderITModel.Store.FK_OrderDetail_Order">
            <End Role="Order" EntitySet="Order" />
            <End Role="OrderDetail" EntitySet="OrderDetail" />
       </AssociationSet>
     </EntityContainer>
     <Association Name="FK_OrderDetail_Order">
       <End Role="Order" Type="OrderITModel.Store.Order" Multiplicity="1">
          <OnDelete Action="Cascade" />
       </End>
       <End Role="OrderDetail" Type="OrderITModel.Store.OrderDetail" Multiplicity="*" />
       <ReferentialConstraint>
          <Principal Role="Order">
            <PropertyRef Name="OrderId" />
          </Principal>
       <Dependent Role="OrderDetail">
            <PropertyRef Name="OrderId" />
       </Dependent>
      </ReferentialConstraint>
    </Association>

修改映射模式(mapping schema)

映射模式并不知道外键关联。但它只需要知道外键属性是如何映射到数据库中的外键

在本例中,将OrderDetail类的OrderId属性映射到OrderDetail表的OrderId列,代码如下:

          <EntitySetMapping Name="OrderDetails">
            <EntityTypeMapping TypeName="OrderITModel.OrderDetail">
               <MappingFragment StoreEntitySet="OrderDetail">
                  <ScalarProperty Name="OrderId" ColumnName="OrderId" />
               </MappingFragment>
            </EntityTypeMapping>
          </EntitySetMapping>

订单和订单详细之间的one-to-one关系就完成了,下面看看如何建立两者的one-to-many关系。

One-to-many 关系

创建one-to-many关系跟创建one-to-one关系仅仅有一点不同。过程跟之前的完全相同,但是因为已经在EDM中添加了关联,你只需修改Order类并在CSDL中反应修改。

给父类(parent class)添加属性

Order类使用名为OrderDetails的集合属性引用它的详细。该属性必须是ICollection<OrderDetail>,ISet<OrderDetail>,或者任何实现了它们的类型,如List<T>或者HashSet<T>。

集合属性在范围是需要被初始化,否则会得到NullReferenceException。如何创建属性要根据你选择的集合类型。如果使用接口,则延迟实例化。如果使用的是真实类型,则可以在构造函数中也可以延迟实例化。
建议始终使用延迟实例化的方法,如下面的清单:

创建引用对象集合的属性
public class Order
{
    private ICollection<OrderDetail> _OrderDetails;
    public ICollection<OrderDetail> OrderDetails
    {
        get
        {
            _OrderDetails = _OrderDetails ?? new HashSet<OrderDetail>();
            return _OrderDetails;
        }
        set
        {
            _OrderDetails = value;
        }
    }
}

修改概念模式(conceptual schema)

在概念模式中给Order描述添加新的属性,跟在OrderDetail中一样,添加一个NavigationProperty,修改Name特性并将Roles反过来,因为这里是从Order到OrderDetail。

 <NavigationProperty Name="OrderDetails" Relationship="OrderITModel.FK_OrderDetail_Order" FromRole="Order" ToRole="OrderDetail" />

就这些。关系已经在CSDL和SSDL中定义了;在MSL没有地方需要修改,因为导航属性不需要映射。

下一个需要分析的关系是many-to-many。在OrderIT中,这种关系存在于products和suppliers。

Many-to-many 关系

创建many-to-many的步骤也是一样的。首先,创建两个类的集合属性关联彼此,然后修改EDM。这种类型关系的不同之处是没有外键属性。类之间是直接的关系,所以数据库中的连接表在模型中没有与之对应的。这就意味着必须使用独立关联(independent association)。

到目前为止,已经看到了类,CSDL和SSDL的相关代码。下面快速回顾一下如何在product和supplie间建立多对多的关系:

1. Product和Supplier需要使用集合属性关联彼此。
2. 在CSDL中,需要映射类和它们的关联,不需要插入外键关联的信息。
3. 在SSDL中,需要声明和定义Product,Company和ProductSupplier表和它们的关联。
4. 在MSL中,需要映射Product和Supplier之间的关系到数据库。

在这一点上,因为没有使用外键关联,必须定义如何关联类,这个工作在映射文件中完成。

修改映射模式(mapping schema)

在映射模式中,使用AssociationSetMapping元素映射数据库列到独立关联(independent association)。AssociationSetMapping元素有三个特性:

1. Name——指定概念模式中的关联名。
2. TypeName——表示概念模式中的关联集(association set)的全名。
3. StoreEntitySet——包含数据库中子表的名称。

在AssociationSetMapping内部,放置两个EndProperty元素,它们的Name特性匹配概念模式中Association节点End元素的Role特性。最后,包含进一个ScalarProperty元素,指定类的属性和连接表的外键列。

映射独立(Independent)属性
          <AssociationSetMapping Name="ProductSupplier" TypeName="OrderITModel.ProductSupplier" StoreEntitySet="ProductSupplier">
            <EndProperty Name="Supplier">
              <ScalarProperty Name="CompanyId" ColumnName="SupplierId" />
            </EndProperty>
            <EndProperty Name="Product">
              <ScalarProperty Name="ProductId" ColumnName="ProductId" />
            </EndProperty>
          </AssociationSetMapping>

结束了!many-to-many关系仅仅需要在映射模式中一个新的标签。在讨论继承之前,先来看看下面的内容。

关于关系的一些Tips

关于关系,首先要知道的是不是必须使用外键关联。例如,可以从OrderDetail中移除OrderId,使用独立关联和Order映射关联。但是使用外键关联比使用独立关联简单,尤其当你存储一个对象图时更是这样。如果可能,我们始终推荐使用外键。

另一件你需要知道的是不能同时使用外键关联和独立关联。你必须选择其中之一使用,设计器强制实施此规则,如果两个同时使用,它则会禁用一个。

如果你不想在many-to-many中使用独立关联,可以遵循LINQ to SQL方法:创建一个类,匹配连接表,然后再将类和表关联。这允许使用外键,但这是很差的设计,我们不建议这样。

下一篇将学习映射继承。

转载于:https://www.cnblogs.com/nianming/archive/2011/10/28/2227699.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/110525.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 轮询和长轮询_http长轮询

    轮询和长轮询_http长轮询轮询:说白了就是客户端定时去请求服务端,是客户端主动请求来促使数据更新;长轮询:说白了也是客户端请求服务端,但是服务端并不是即时返回,而是当有内容更新的时候才返回内容给客户端,从流程上讲,可以理解

  • java语言代码大全_java语言代码大全解析

    java语言代码大全_java语言代码大全解析Java语言是如今互联网最热门的语言之一,今天我们就来了解一些java语言经常用到的代码,快来看看吧。一、jdbc连接publicclassOracleJdbcTest{StringdriverClass=”oracle.jdbc.driver.OracleDriver”;Connectioncon;publicvoidinit(FileInputStreamfs)throws…

  • ORACLE存储过程的分支语法(IF语句)

    ORACLE存储过程的分支语法(IF语句)基本语法1.if条件then语句1;语句2;endif;2.if条件then语句序列1;esle语句序列;endif;3.if条件then语句;elsif语句then语句;else语句;endif;…

  • 配置设置文件怎么生成的_centos6.8网络配置

    配置设置文件怎么生成的_centos6.8网络配置前言每个测试用例都应该有config部分,可以配置用例级别。比如name、base_url、variables、verify、export等等案例演示fromhttprunnerimport

  • 数组求和的方法_vb怎么求和数组里的值

    数组求和的方法_vb怎么求和数组里的值对于数组求和有多种方法:1:递归方法functionsum(arr){ varlen=arr.length; if(len==0){  return0; }elseif(len==1){  returnarr[0]; }else{  returnarr[0]+sum(arr.slice(1)); }}vara=newArray(1…

  • 爆笑三国之张飞流水账【爆笑中体验哲理】「建议收藏」

    爆笑三国之张飞流水账【爆笑中体验哲理】「建议收藏」
    张飞流水帐一
    我写这个流水帐的时候,大哥和二哥都在睡觉,军师也在睡觉。
    赤兔马站在我窗外,也在睡觉。
      小时侯我就研究马为什么会站着睡觉,研究了很长一段时间后,我发现没有答案。而苦恼的是我的童年唯一能记起的事就是这个了。

      长大以后有段时间我开始研究大哥和二哥为什么要睡在一张床上,同样也没有答案。
      这个世界有太多的事是没有答案的,军师对我说过。
      在我睁大眼睛思考问题的时候,我养成了睁眼睡觉的习惯,不

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号