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)


相关推荐

  • 流水线设计的方法和作用「建议收藏」

    流水线设计的方法和作用「建议收藏」流水线设计从某种程度上可以提高系统频率,因此常用于高速信号处理领域,如果某个信号可以分为若干步骤处理,而且整个数据处理过程是单项的,即没有反馈运算和迭代运算,前一个步骤的输出就是下一个步骤的输入,可以考虑流水线设计来提高系统的频率。如下图所示:典型的流水线设计是将原本一个时钟周期完成的较大的组合逻辑通过合理的切割后分由多个时钟周期来完成,这样一来该部分逻辑运行的时钟频率就会有明显的提升,尤其当她是…

  • 自然语言处理中的N-Gram模型详解

    自然语言处理中的N-Gram模型详解N-Gram(有时也称为N元模型)是自然语言处理中一个非常重要的概念,通常在NLP中,人们基于一定的语料库,可以利用N-Gram来预计或者评估一个句子是否合理。另外一方面,N-Gram的另外一个作用是用来评估两个字符串之间的差异程度。这是模糊匹配中常用的一种手段。本文将从此开始,进而向读者展示N-Gram在自然语言处理中的各种powerful的应用。

  • 过滤器与拦截器详解图_过滤器 拦截器

    过滤器与拦截器详解图_过滤器 拦截器过滤器详解依赖于servlet容器,实现基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,过滤器一般用于登录权限验证、资源访问权限控制、敏感词汇过滤、字符编码转换等等操作,便于代码重用,不必每个servlet中进行冗余操作。Java中的Filter并不是一个标准的Servlet,它…

  • Java中Future的使用场景和解析

    Java中Future的使用场景和解析

  • getproperty方法_setter什么意思

    getproperty方法_setter什么意思PropertyDescriptor获取属性的getter/setter方法

  • Autoencoder自动编码器的发展

    Autoencoder自动编码器的发展Autoencoder自动编码器的发展0、玻尔兹曼机中的测试实验——编码问题(1985)0.1、玻尔兹曼机0.2、受限的玻尔兹曼机0.3、编码问题——自动编码器雏形1、反向传播中的仿真——单层自动编码器(1986)2、利用神经网络进行数据降维——深度自动编码器(2006)3、去噪自编码器(2008)4、稀疏自编码器(2011)5、卷积自编码器(2011)6、变分自编码器(2013)6.1、模型6….

发表回复

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

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