Hey Jonathan,

You were absolutely right. What I didn't mention before (because I
didn't think it was relevant) is that all the code I've been
describing is in the context of RSpec tests. After your last message,
I took a look at the fixture in my before method. It turns out that
for the children I had provided my own id value before asking
DataMapper to create the entries that I later attempt to update and
verify during the course of my tests. I removed the ids, refactored my
tests, and refactored my code to be tighter as you suggested, and now
everything works just fine without a need to reset anything.

It may very well be that my code would've worked during the course of
"real" operation because I wouldn't have done any hardcoded creation
of entities, but testing things with RSpec and applying your guidance
taught me a lot.

Thanks.


On Jan 15, 11:42 am, Jonathan Stott <[email protected]> wrote:
> Hi Neil
>
> That all looks like it should work.  How did this stuff get into the
> DB in the first place, then?  That now seems like the most likely
> source of the error.
>
> Also, you can simplify 'create_child_from' somewhat by doing:
>
> def self.create_child_from(name)
>   Child.new(:name => name)
> end
>
> You could even do this:
>
> parent.children.new(:name => name)
>
> to pre-assign the parent.
>
> Regards
> Jonathan
>
> On 15 January 2012 15:42, Neil Chaudhuri <[email protected]> wrote:
>
>
>
>
>
>
>
> > Hey Jonathan,
>
> > I took a look at what I'm doing with ids, and I don't think I am
> > messing with ids at all. In my update of the existing children, I
> > don't update their ids. When I create the new child instance in
> > memory, I don't give it an id at all because the id property is a
> > Serial type in my DataMapper model.
>
> > I've talked enough, so here is some code:
>
> > def self.update_children(parent, children_hash)
> >    parent.children.each do |child|
> >      name_to_status_hash = children_hash[child.id.to_s]
> >      unless name_to_status_hash.nil?
> >        updated = child.update(
> >            {
> >                :status => name_to_status_hash[child.name]
> >            })
> >      end
> >    end
> > end
>
> > where children_hash looks like this:
>
> > children_hash = {
> >        "1"=>{"Bobby"=>"true"},
> >        "2"=>{"Sue"=>"false"}
> > }
>
> > As you can see, I am iterating through the child collection from the
> > parent, and for each child's id I am grabbing the value from the
> > children_hash provided by a controller and updating only the status.
> > Not touching the id.
>
> > Now here is the code for creating a new child:
>
> > def self.create_child_from(name)
> >    child = Child.new
> >    child.attributes = {
> >        :name => name
> >    }
> >    child
> > end
>
> > Only name is required, so I populate that. But you'll notice no id
> > value.
>
> > So I am still fairly confused. At least the code works with the
> > sequence reset!
>
> > Thanks.
>
> > On Jan 15, 5:35 am, Jonathan Stott <[email protected]> wrote:
> >> Hi Neil
>
> >> From the sequence of events you've described below, it seems the
> >> problem is that one of your updates of the existing children is
> >> updating the record id too and putting that beyond the end of the
> >> sequence.  Or that one of your create_child_from(data) calls is
> >> creating a record with the same.  DataMapper doesn't stop you from
> >> doing this, as it's valid in SQL, and the authors assume if you want
> >> to do it, you have good reason.
>
> >> In terms of documentation being dated, I wouldn't worry too much.
> >> DataMapper takes the stability of its API /very/ seriously.  The
> >> public behaviour of the save() and update() methods definitely hasn't
> >> changed since 1.0.0 was released (in 2010) and was pretty stable for a
> >> long time before that.
>
> >> As for a more 'elegant' way of doing this, I'm not sure that there is
> >> one.  Wrapping the whole thing in a transaction might improve your
> >> storage efficiency a little bit.  Also, looking more toward the
> >> future, updating all the attributes via "resource.attributes =
> >> new_values" and then triggering the update process with a save of the
> >> parent right at the end might allow an adapter to generate a large sql
> >> call instead of lots of little ones, but that's hypothetical.
>
> >> Regards
> >> Jonathan
>
> >> On 15 January 2012 04:05, Neil Chaudhuri <[email protected]> wrote:
>
> >> > Hey Jonathan,
>
> >> > Assume I have a Parent instance fetched from the database (Postgres)
> >> > and it has some existing Child instances (as the Parent and Child
> >> > instances were all created at the same time). The first thing I did is
> >> > call
>
> >> > existing_parent.update(new_parent_values)
>
> >> > ...which updates values in the Parent instance but nothing related to
> >> > the children.
>
> >> > Then to update the children I did this
>
> >> > existing_parent.children.each do |child|
> >> >      updated = child.update( { #values })
> >> > end
>
> >> > ...which makes some changes to the existing children that are
> >> > persisted just fine.
>
> >> > Then I want to add a NEW child to the children collection, which I did
> >> > this way
>
> >> > existing_parent.children << create_child_from(data)
> >> > #create_child_from(data) creates a new Child instance in memory and
> >> > populates it with data
> >> > existing_parent.save
>
> >> > It is on this third operation where I get the sequence error.
>
> >> > Executing the reset sequence statement beforehand does indeed help, so
> >> > that solves the problem technically.
>
> >> > I would still love to know if there is a more efficient or elegant way
> >> > to do the same sort of thing--in fact, for all the operations of
> >> > updating the parent, then updating the existing children, then adding
> >> > a brand new child. The documentation I've been reading seems a bit
> >> > dated.
>
> >> > Thanks.
>
> >> > On Jan 14, 8:39 am, Jonathan Stott <[email protected]> wrote:
> >> >> Hi Neil
>
> >> >> Errors like that tend to occur if you've imported a whole bunch of
> >> >> pre-existing records into the database/table without updating the
> >> >> sequence.  Ideally you should never need to run it, but if you have
> >> >> to, the time to do it is just after you've performed the DB import
> >> >> task.  If you haven't just done that, can you explain what you did
> >> >> before the errors occured?
>
> >> >> I'm not sure DataMapper has any explicit support for this.
>
> >> >> Regards
> >> >> Jonathan
>
> >> >> On 14 January 2012 00:54, Neil Chaudhuri <[email protected]> wrote:
>
> >> >> > Apparently, the reason why updates won't save is a sequence issue as
> >> >> > found 
> >> >> > here:http://railspikes.com/2009/3/6/duplicate-key-violates-unique-constraint
>
> >> >> > So I suppose I need to do something like this: select
> >> >> > setval('children_id_seq', (select max(id) + 1 from children));
>
> >> >> > I have two questions as I am not a DBA:
>
> >> >> > 1) When exactly do I do this? Every time I want to insert a child
> >> >> > record?
> >> >> > 2) Why doesn't DataMapper handle this? Maybe I am spoiled by using
> >> >> > Hibernate in the Java world, but they handle sequences fairly easily
> >> >> > by using what they call dialects. I assumed the database-specific
> >> >> > DataMapper gems would do something similar. Or maybe they do and I am
> >> >> > just missing it?
>
> >> >> > Thanks.
>
> >> >> > On Jan 13, 1:14 pm, Neil Chaudhuri <[email protected]> wrote:
> >> >> >> I have been able to create a 1:M relationship using DataMapper and
> >> >> >> update the child items as well after creation. However, I have been
> >> >> >> unable to add to that collection.
>
> >> >> >> Let's say I have
>
> >> >> >> class Parent
> >> >> >>   include DataMapper::Resource
>
> >> >> >>   property :id, Serial
> >> >> >>   ...
>
> >> >> >>   has n, :children
> >> >> >> end
>
> >> >> >> class Child
> >> >> >>   include DataMapper::Resource
>
> >> >> >>   property :id, Serial
> >> >> >>   ...
> >> >> >>   belongs_to :parent
> >> >> >> end
>
> >> >> >> Whenever I try to add to the child collection belonging to a certain
> >> >> >> parent instance, I get either DataMapper::UpdateConflictError or
> >> >> >> "DataObjects::IntegrityError: ERROR:  duplicate key value violates
> >> >> >> unique constraint "children_pkey" DETAIL:  Key (id)=(1) already
> >> >> >> exists.
>
> >> >> >> I have tried a whole host of approaches. The most promising seemed
> >> >> >> parent.children.create(attributes), but that led to the
> >> >> >> IntegrityError. What is the preferred approach for adding a new item
> >> >> >> to the collection?
>
> >> >> >> Thanks.
>
> >> >> > --
> >> >> > You received this message because you are subscribed to the Google 
> >> >> > Groups "DataMapper" group.
> >> >> > To post to this group, send email to [email protected].
> >> >> > To unsubscribe from this group, send email to 
> >> >> > [email protected].
> >> >> > For more options, visit this group 
> >> >> > athttp://groups.google.com/group/datamapper?hl=en.
>
> >> > --
> >> > You received this message because you are subscribed to the Google 
> >> > Groups "DataMapper" group.
> >> > To post to this group, send email to [email protected].
> >> > To unsubscribe from this group, send email to 
> >> > [email protected].
> >> > For more options, visit this group 
> >> > athttp://groups.google.com/group/datamapper?hl=en.
>
> > --
> > You received this message because you are subscribed to the Google Groups 
> > "DataMapper" group.
> > To post to this group, send email to [email protected].
> > To unsubscribe from this group, send email to 
> > [email protected].
> > For more options, visit this group 
> > athttp://groups.google.com/group/datamapper?hl=en.

-- 
You received this message because you are subscribed to the Google Groups 
"DataMapper" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/datamapper?hl=en.

Reply via email to