【问题标题】:Setting up Associations with DataMapper & Sinatra使用 DataMapper 和 Sinatra 建立关联
【发布时间】:2011-11-23 05:33:14
【问题描述】:

好的,这让我发疯了。我已经阅读了协会的文章和示例,并且在过去的三天里一直在努力解决这个问题,我厌倦了这让我感到愚蠢,所以......

如何与 DataMapper 建立关联?

(我正在使用带有 SQLite3 的 Sinatra 的 DM。对于具有多个值等的单个表来说,一切都很好。当我开始尝试将它们关联起来时,我开始遇到错误。)

假设我有一个种满苹果树的果园。每棵树都有很多苹果。每个苹果都有许多种子。因此,每棵树的苹果都有很多种子

require 'sinatra'
require 'datamapper'

DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/orchard.db")

# Trees in the orchard.
class Tree
  include DataMapper::Resource
  property :id, Serial

  has n, :apples
  has n, :seeds, :through => :apples
end

# Apples on a Tree.
class Apple
  include DataMapper::Resource
  property :id, Serial

  belongs_to :tree
  belongs_to :seed
end

# Seeds in an Apple
class Seed
  include DataMapper::Resource
  property :id, Serial

  has n, :apple
  has n, :tree, :through => apple 
end

DataMapper.finalize.auto_upgrade!

正确吗?当我尝试运行它时,我不断收到各种错误。主要是无效关联或无法创建值为 NULL 的列 NULL 等。我对这种关系有什么不了解?

此外,一旦我有了一个工作模型,我该如何从中获取信息?

如果有 3 棵树:

Tree.all.count 
=> 3

如果有 2 个苹果:

Apple.all
=>[#<Apple @id=1>, #<Apple @id=2>]  

好的,酷。 但是树#2 有多少个苹果呢? 树#4有多少种子? 一共有多少个苹果? 一共有多少颗种子?

任何帮助将不胜感激。

【问题讨论】:

    标签: ruby sinatra datamapper


    【解决方案1】:

    您的模型似乎有点混乱:

    假设我有一个种满苹果树的果园。每棵树都有很多苹果。每个苹果都有许多种子。因此,每棵树的苹果都有许多种子。

    所以一棵树有很多苹果,一个苹果属于一棵树并有很多种子,一个种子属于一个苹果(最终是一棵树)。

    我们几乎(但不完全)可以按原样使用该语言并使用它来创建关联。经过一些翻译以得到正确的语法,我们得到了这个:

    # Trees in the orchard.
    class Tree
      include DataMapper::Resource
      property :id, Serial
    
      has n, :apples    # "a tree has many apples"
      has n, :seeds, :through => :apples
    end
    
    # Apples on a Tree.
    class Apple
      include DataMapper::Resource
      property :id, Serial
    
      belongs_to :tree # "an apple belongs to a tree..."
      has n, :seeds    # "...and has many seeds"
    end
    
    # Seeds in an Apple
    class Seed
      include DataMapper::Resource
      property :id, Serial
    
      belongs_to :apple  # "and a seed belongs to an apple"
    end
    

    在您的代码中,您的种子有多个苹果和树木,这实际上没有任何意义。

    关于查询:

    但是树 #2 有多少个苹果?

    假设您的意思是Treeid == 2

    tree_2 = Tree.get(2)
    apples_of_tree_2 = tree_2.apples # this gives an array of apples
    count_of_apples_of_tree_2 = tree_2.apples.count
    

    4 号树有多少颗种子?

    我们添加到Tree 模型has n, :seeds, :through =&gt; :apples 的关联意味着我们在Tree 对象中提供了一个seeds 方法。

    Tree.get(4).seeds.count
    

    总共有多少个苹果?一共有多少颗种子?

    简单地说:

    Apple.count  # note singular not plural (it's a class method on Apple)
    Seed.count
    

    尝试将这个新模型加载到 irb 中(您可能需要在更改模型时删除您的 orchard.db 文件),然后使用一些 queriescreation methods,希望这会给您更好地了解正在发生的事情。

    创建关联

    (请参阅the Associations page 上的“添加到关联”部分。)

    要将现有的Apple 添加到Tree

    a_tree.apples << an_apple
    

    请注意,Tree 不是与单个 Apple 相关联,而是与一个集合相关联(它是 has n Apples),因此创建的方法是 apples(即它是复数形式),并且没有方法apple 这就是您看到 no method 错误的原因。

    您也可以直接创建与Tree 关联的新Apple

    a_tree.apples.new    #created but not saved to database
    a_tree.apples.create #created and saved to database
    

    您也可以从Apple 端反过来创建关联:

    an_other_apple = Apple.new
    an_other_apple.tree = a_tree
    

    但您需要小心这样做,因为新苹果不会出现在Applesa_trees 集合中(a_tree.apples 不会包括an_other_apple)。为了让它出现你需要保存苹果,然后在Tree上调用reload

    an_other_apple.save
    a_tree.reload
    

    您需要注意这一点,因为如果您不小心,您最终可能会得到一个似乎同时存在于两个Trees 中的Apple

    【讨论】:

    • 非常感谢!我能够让我的数据库结构正常工作。我阅读了有关查询和创建方法的文档,但对于如何为特定树创建苹果或为特定苹果创建种子,我仍然有些困惑。
    • 在 IRB tree.apple = Tree.new 中为 'apple=' 产生未定义的方法我认为这意味着我没有选择适当的目标或传递正确的属性。在特定树上创建新 Apple 的命令是什么?还是特定苹果中的种子?
    • @DonGraziano 我添加了一些创建关联的示例。我希望这些帮助。
    • 感谢您的帮助。出于某种原因,它只是没有点击阅读文档和其他人的示例。我只有最后一个问题。假设每个模型也有一个名称值,tree_name、apple_name、seed_name。我希望能够找到那个名字。 IE。 Tree.get('Wanda') 但如果我将 :key, =&gt; true 添加到树名 Tree.get('Wanda') 告诉我属性错误 1 ​​为 2。Tree.get(1, 'Wanda') 返回 &lt; @Id = 1, @tree_name = "Wanda"&gt;。我阅读了 te Docs 并认为添加 :key, =&gt; true 可以添加到任何属性以使其成为键值。
    • @DonGraziano 添加property :name, String, :key =&gt; true 同时保留property :id, Serial 行将创建一个复合键(idname)。使用get,您需要指定整个密钥来识别记录,因此您需要Tree.get(1, 'Wanda')。删除 id 属性将使键仅保留名称,因此 Tree.get('Wanda') 将起作用(在这种情况下,名称需要是唯一的)。
    【解决方案2】:

    我认为这是一个多元化问题 - 你不讨厌吗?

    # Seeds in an Apple
    class Seed
      include DataMapper::Resource
      property :id, Serial
    
      has n, :apples  # here
      has n, :tree, :through => :apples  # and here
    end
    

    【讨论】:

      【解决方案3】:

      在没有太多Datamapper知识的情况下,跳过datamapper文档后,这些答案怎么样?

      树 2 有多少个苹果:

      Tree.get(2).apples.count
      

      树 4 有多少种子:

      Tree.get(4).apples.inject(0) {|count, apple| count + apple.seeds.count}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-05
        • 1970-01-01
        • 1970-01-01
        • 2011-01-18
        • 2011-07-14
        相关资源
        最近更新 更多