weixin_39782500 2020-11-22 01:58
浏览 0

Assigning a parent to a child does not work the same as assigning a child to a parent

This bug makes it hard to create complex object graphs because you have to be careful to create the objects by assigning children to parents. If you do it the other way round, the objects don't save, because the parent isn't aware it has a child to save. You can see this in the following example, which has one example passing and one failing:

 ruby
require 'rubygems'

USE_DM_0_9 = false

if USE_DM_0_9
  DM_GEMS_VERSION   = "0.9.11"
  DO_GEMS_VERSION   = "0.9.12"
else
  DM_GEMS_VERSION   = "0.10.0"
  DO_GEMS_VERSION   = "0.10.0"
end

gem "data_objects",    DO_GEMS_VERSION
gem "do_postgres",     DO_GEMS_VERSION # If using another database, replace this
gem "dm-core",         DM_GEMS_VERSION         
gem "dm-aggregates",   DM_GEMS_VERSION   
gem "dm-migrations",   DM_GEMS_VERSION   
gem "dm-timestamps",   DM_GEMS_VERSION   
gem "dm-types",        DM_GEMS_VERSION        
gem "dm-validations",  DM_GEMS_VERSION  
gem "dm-serializer",   DM_GEMS_VERSION  

require "data_objects"
require "do_postgres"
require "dm-core"
require "dm-aggregates"
require "dm-migrations"
require "dm-timestamps"
require "dm-types"
require "dm-validations"
require "dm-serializer"

require 'spec'

# SQLITE_FILE = File.join(`pwd`.chomp, "test.db")

# DataMapper.setup(:default, "sqlite3:#{SQLITE_FILE}")
# DataMapper.setup(:reloaded, "sqlite3:#{SQLITE_FILE}")

DataMapper.setup(:default, "postgres://andy/datamapper_test")
DataMapper.setup(:reloaded, "postgres://andy/datamapper_test")

class Parent
  include DataMapper::Resource
  property :id, Serial
  property :name, String, :nullable => false

  validates_is_unique :name

  has n, :kids, :order => [:name]

  def ==(other)
    other.kids == kids && other.name == name
  end

  def the_same_when_you_do_the_comparison_the_other_way_round?(other)
    other.name == name && other.kids == kids
  end
end

class Kid
  include DataMapper::Resource
  property :id, Serial
  property :name, String

  belongs_to :parent, :model => "Parent", :child_key => [:parent_id]  

  validates_is_unique :name, :scope => :parent
end

module IdentityMapHelper
  def reload(object)
    object.class.get(object.id)
  end

  def with_db_reconnect(&blk)
    original_repository = DataMapper::Repository.context.pop
    repository(:reloaded, &blk)
    DataMapper::Repository.context << original_repository
  end
end

Spec::Runner.configure do |config|
  include IdentityMapHelper

  config.before(:each) do
    Parent.auto_migrate!
    Kid.auto_migrate!
  end

  config.before(:each) do    
    DataMapper::Repository.context << repository(:default)
  end

  config.after(:each) do
    DataMapper::Repository.context.pop
  end
end

describe Parent, "with kids, 1 to n" do
  it "should have let the parent know it's got a kid" do
     = Parent.new(:name => "Andy")
     = Kid.new(:name => "Bart", :parent => )

    .parent.should == 
    .should have(1).kids
  end

  it "should let the kid know who it belongs to" do
     = Kid.new(:name => "Bart")
     = Parent.new(:name => "Andy", :kids => [])

    .should have(1).kids
    .parent.should == 
  end
end

Created by Ashley Moran - 2009-07-01 12:12:46 UTC

Original Lighthouse ticket: http://datamapper.lighthouseapp.com/projects/20609/tickets/939

该提问来源于开源项目:datamapper/dm-core

  • 写回答

11条回答 默认 最新

  • weixin_39782500 2020-11-22 01:58
    关注

    This ticket actually goes back quite a way to #488. I’m going to leave this here though because it has specs ;) (even though we actually have had pending specs for this in dm-core/next for 4 or 5 months)

    Now that alot of the Relationship#inverse issues have been worked out this should be relatively easy to tackle. (knowing the inverse relationship is really the only way to do this reliably)

    The basic approach will be that when appending a child to a collection of children, the child will be related to the parent (child.parent.should equal(parent)). Conversely, when assigning a parent to a child, we will do parent.children << child behind the scenes -- provided that the child does not already exist in the collection.

    by Dan Kubb (dkubb)

    评论

报告相同问题?