
Assigning a parent to a child does not work the same as assigning a child to a parent
Reported by Ashley Moran | July 1st, 2009 @ 07:12 AM
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:
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@localhost/datamapper_test")
DataMapper.setup(:reloaded, "postgres://andy@localhost/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 = Parent.new(:name => "Andy")
@kid = Kid.new(:name => "Bart", :parent => @parent)
@kid.parent.should == @parent
@parent.should have(1).kids
end
it "should let the kid know who it belongs to" do
@kid = Kid.new(:name => "Bart")
@parent = Parent.new(:name => "Andy", :kids => [@kid])
@parent.should have(1).kids
@kid.parent.should == @parent
end
end
Comments and changes to this ticket
-
Dan Kubb (dkubb) July 3rd, 2009 @ 02:55 AM
- Assigned user set to Dan Kubb (dkubb)
- State changed from new to accepted
-
Dan Kubb (dkubb) July 3rd, 2009 @ 03:13 AM
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.
-
Dan Kubb (dkubb) July 7th, 2009 @ 10:33 AM
That's interesting. It might be a problem, but I'm not sure yet. I'll have to see if I can put together a few models with ambiguous relationships and see if I can reason out how to handle it.
-
Dan Kubb (dkubb) October 4th, 2009 @ 09:33 PM
- Milestone changed from 0.10.0 to 0.10.2
[project:id#20609 not-tagged:"0.10.0" milestone:id#51895 bulk edit command]
-
Dan Kubb (dkubb) February 1st, 2010 @ 04:33 PM
- Milestone changed from 0.10.2 to 1.0.0
-
-
-
Dan Kubb (dkubb) February 2nd, 2010 @ 02:47 AM
- State changed from accepted to confirmed
-
Dan Kubb (dkubb) March 10th, 2010 @ 03:22 AM
Ashely, I only really follow the tickets I or other people are actively working on. When I finish a ticket, and have available bandwidth I generally tackle the issues that affect my work, and if there aren't any of those, tickets that are most often reported.
While this can bite people, I've only heard it reported a couple of times in several years .. if there were more +1's or mentions on the mailing list, IRC or elsewhere it would certainly get bumped up in priority.
Also lately I've had to cut my time spent on DM from 60-80 hours a week down to 5-10, and am hoping that the community will step up and help fix simpler issues like this. It's not sustainable for (almost) every fix to be dependent on me, and by pulling back I am starting to see others in the community help with fixes and improvements like snusnu and solnic, among several others.
I will add a comment in #1042
Please Sign in or create a free account to add a new ticket.
With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »