• Ruby on rails开发从头来(五十六) ActiveRecord基础(一对多关联关系)


          一对多关联可以使我们表示一组对象,例如,一个order可以包含有任意多个line item,在数据库中,所有的line item记录都通过外键关联到特定的order

        Active Record中,通过在父对象中的has_many来定义到子对象的关联,在子对象中使用belongs_to来指定父对象。我们已经在上一篇中了解了belongs_to声明,实际上,在一对多的情况下,和一对一是相同的,所以我们来了解has_many声明。

     

    has_many声明

        has_many声明了一个属性,其行为就像一组子对象,可以把它看作数组来访问,查询特定的对象,或者添加新对象。例如:

    order = Order.new

    params[:products_to_buy].each do |prd_id, qty|

    product = Product.find(prd_id)

    order.line_items << LineItem.new(:product => product,

    :quantity => qty)

    end

    追加操作符(>>)所作的不仅仅是向orderline_items列表中追加一个对象,并且和设置了line_item对象外键值为order对象主键值,而且在order对象保存的时候,会同时保存line_item对象。

    我们可以像对数组一样对has_many关联进行循环:

    order = Order.find(123)

    total = 0.0

    order.line_items.each do |li|

    total += li.quantity * li.unit_price

    end

    has_one一样,我们可以改变Active Record的默认形式,我们可以给has_many一组设定,:class_name:foreign_key:conditions:order:dependenthas_one中的是一样的,has_many还有:exclusively_dependent:finder_sql:counter_sql

    has_onehas_many都支持:dependent,这告诉Rails在删除主表中记录的同时删除从表中对应的记录。也就是对所有外键为删除的主记录的id的子对象调用它们destory方法。

    无论如何,如果从表仅仅和主表关联,而没有其他表关联,而且没有任何钩子方法在删除的时候执行操作,你可以使用:exclusively_dependent来代替:dependent,在这种情况下,对于所有的子记录会使用一条sql语句来删除,这样执行速度会快一点。

    你还可以通过使用:finder_sql:counter_sql设定来复写Active Record用来对子记录进行查询和计数的sql。在:conditions设定不足够的情况下,这两个设定就很有用了。例如:

    class Order < ActiveRecord::Base

    has_many :rails_line_items,

    :class_name => "LineItem",

    :finder_sql => "select l.* from line_items l, products p " +

    " where l.product_id = p.id " +

    " and p.title like '%rails%'"

    end

    :counter_sql设定用来复写Active Record用作计算行数的sql,如果:finder_sql被指定了,但是:counter_sql没有指定,Active Record将会根据查询sql来替换计算行数的sql

    :order设定指定了从数据库中选出的记录的排序所使用的sql,如果你在遍历记录集的时候需要有特定的排序,你就需要指定:order,也就是设定sql语句的order by部分,默认情况下,所有的字段都是升序。例如:

    class Order < ActiveRecord::Base

    has_many :line_items,

    :order => "quantity, unit_price DESC"

    end

    现在再回到has_one声明,我们前面提到过也支持:order,但是一条父记录最多只有一条子记录,那么为什么要支持:order来允许指定排序条件呢?想象一下这样的场景,一个用户可能有多条订单,但是,如果我们想查看该用户的最新一条订单呢?这时候,我们就可以使用has_one声明了:

    class Customer < ActiveRecord::Base

    has_many :orders

    has_one :most_recent_order,

    :class_name => 'Order',

    :order => 'created_at DESC'

    end

    上面的代码创建了一个新属性:most_recent_order,将会引用到该用户的最新一条订单,我们可以这样使用它:

    cust = Customer.find_by_name("Dave Thomas")

    puts "Dave last ordered on #{cust.most_recent_order.created_at}"

    实际上,Active Record执行了下面的sql

    SELECT * FROM orders

    WHERE customer_id = ?

    ORDER BY created_at DESC

    LIMIT 1

    根据前面我们学习的find方法,可以看到只取了排序后的第一条记录。

     

    has_many添加的方法

    就像belongs_tohas_onehas_many也添加了一组属性相关的方法在它所在的类中,下面我们来看看这些方法,我们的声明是这样

    class Customer < ActiveRecord::Base

    has_many :orders

    end

    l         orders(force_reload=false)=

    返回一个和用户关联的订单的数组,结果集是被缓存的,对于相同的查询,不会再次从数据库提取数据,除非force_reload = true

    l         orders <<order

    添加订单到指定用户的订单的列表中。

    l         orders.push(order1, ...)

    添加一个或多个订单对象到用户的订单列表中,concat()是该方法的别名。

    l         orders.delete(order1, ...)

    从用户的订单列表中删除一个或多个订单,但是不会删除数据库中对应的记录,只是将它们的customer_id外键设置为null,断开和用户的关联。

    l         orders.clear

    分离用户和订单,就像delete(),但是如果订单被指明为:dependent,数据库中对应的记录就会被删除。

    l         orders.find(options...)

    发出一个find()调用,但是仅返回用户关联的订单。

    l         orders.build(attributes={})

    构造一个新的order对象,用给定的属性初始化,并且关联到customer,该对象没有保存。

    l         orders.create(attributes={})

    构造并且保存一个新的order对象,用给定的属性初始化,并且关联到customer
  • 相关阅读:
    eclipse编写js代码没有提示
    eclipse安装阿里编码规约插件
    eclipse汉化
    异常: Recieved SHUTDOWN signal from Resourcemanager ,Registration of NodeManager failed, Message from ResourceManager: NodeManager from localhost doesn't satisfy minimum allocations, Sending SHUTDOWN s
    异常: Call From * 9000 failed on connection exception: java.net.ConnectException: Connection refused: no further information; For more details see: http://wiki.apache.org/hadoop/ConnectionRefused
    异常:android.os.NetworkOnMainThreadException
    异常:getHibernateFlushMode is not valid without active transaction; nested exception is org.hibernate.HibernateException: getHibernateFlushMode is not valid without active transaction getHibernateFlu
    异常: Bean named 'org.springframework.transaction.interceptor.TransactionInterceptor#0' is expected to be of type 'org.aopalliance.aop.Advice' but was actually of type 'org.springframework.transaction.i
    JVM GC算法
    设计模式-抽象工厂模式
  • 原文地址:https://www.cnblogs.com/dahuzizyd/p/ruby_rails_study_56.html
Copyright © 2020-2023  润新知