Updating references after BLB Save()

Updating references after BLB Save()

Old forum URL: forums.lhotka.net/forums/t/5546.aspx


Michael posted on Monday, October 06, 2008

I have just upgraded from 3.0.4 to 3.5. I have had to update many of my unit tests with code similar to:

MyBusinessListBase   m_list;
List<MyBusinessBase> m_listToDelete = new List<MyBusinessBase>();

[SetUp]
public void SetUp()
{
  m_list =
MyBusinessListBase.GetMyBusinessListBase();
}

[TearDown]
public void TearDown()
{
  foreach (MyBusinessObject obj in m_listToDelete)
    m_list.Remove(obj);

  m_list = m_list.Save();
  m_list = null;
}

[Test]
...

private MyBusinessBase Insert()
{
  MyBusinessBase obj = m_list.AddNew();
  obj.Name = "Test";
  m_listToDelete.Add(obj);

  // In 3.0.4, the obj added to m_listToDelete had the correct @@IDENTITY
  // after the Save(), but not in 3.5
  m_list = m_list.Save();

  return obj;
}

I have updated Insert() as follows:

  MyBusinessBase obj = m_list.AddNew();
  obj.Name = "Test";

  int index = m_list.IndexOf(obj);

  m_list = m_list.Save();

  obj = m_list[index];

  m_listToDelete.Add(obj);

  return obj;


Is there a better way of doing this? Is the index guaranteed to be the same?

Thanks in advance.

RockfordLhotka replied on Monday, October 06, 2008

3.5 switched the CslaAutoCloneOnUpdate setting from default of false to default of true. This is noted in the breaking changes in the change log. This means the data portal clones your object and requires that you do this:

obj = obj.Save()

The reason for this is documented in other threads - but comes down to the reality that the pre-3.5 behavior was just plain broken and wrong.

There are two solutions.

  1. You can adapt your code to recognize that Save() always returns a new instance of the object graph.
  2. You can set CslaAutoCloneOnUpdate to false, reverting to the older, broken behavior - though it would make your test code work

Eventually I'll get rid of the auto-clone option, this is a multi-version transition (I introduced it in 3.0, changed the default in 3.5 and will perhaps get rid of it in 4.0 or something). So in the end you really need to consider changing your code to deal with the result of the Save() method.

Michael replied on Monday, October 06, 2008

Thanks for the very fast reply, Rocky. I don't want to use "old and busted", I want the "new hotness".

Is recording the index the best way to update the reference to the child after the save?

RockfordLhotka replied on Monday, October 06, 2008

Well, maybe.

 

The whole reason Save() returns a new object graph, is that you don’t know what the save operation actually did to the object graph.

 

OK, you can know, because you write DataPortal_Update() – prior to 3.5 anyway, and even in 3.5 you can write it if you want.

 

I would say that normally the index won’t change, that’s true. All insert/update operations should happen in-place without changing the order, and that’s how the default DataPortal_Update() is written. Obviously deleted items are gone.

 

Rocky

 

 

From: Michael [mailto:cslanet@lhotka.net]
Sent: Monday, October 06, 2008 8:37 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Updating references after BLB Save()

 

Thanks for the very fast reply, Rocky. I don't want to use "old and busted", I want the "new hotness".

Is recording the index the best way to update the reference to the child after the save?


Pawz replied on Monday, October 06, 2008

Perhaps it would be simpler to just record the Ids of the objects you want to delete, rather than the objects themselves? Otherwise you'll be chasing your object references wherever they go.

If you have a list of the IDs of the objects, all you'd need to do would be to load up the main list again and loop through and delete the matching ones - ensuring you're protected from any DataPortal changes in the future...

Michael replied on Monday, October 06, 2008

I had thought about that, and you're probably right. As I get further into updating the unit tests it's becoming more of an issue.

The main part of my question was how to actually get the ID of the newly saved object in the first place. I'm using the index strategy which is working for now.

Pawz replied on Monday, October 06, 2008

That's one of the main reasons I ended up going with the Guid as the primary key for my tables - generating those IDs on the client makes life a lot easier!

On the other hand, using the index of a list.... how do you know you've actually got the correct Id? (Assuming that it's an int-based identity column). And shouldn't the newly returned, saved object contain that Id (or else how would it update itself with further changes?)

Michael replied on Monday, October 06, 2008

Yeah, I had a long hard think and did some research before deciding to go with plain old ints for ID's. One thing I do like is being able to query the database easily.

The problem is the object is a BLB. So, the new children in the returned list have their ID's updated, but the only way I know which child is which is either using an index, or iterating through the list if it happens to have another uniqueness constraint.

Copyright (c) Marimer LLC