Refetch related collection problem

Posts   
 
    
Meteor
User
Posts: 67
Joined: 06-Apr-2007
# Posted on: 03-Mar-2009 02:58:13   

I'm using adapter on 2.6 Final against a MySql database with .Net 3.5 c# templates.

I have a line entity (representing a rail line) and it has a collection of stops using m:n relation in the database (linestops). Therefore within the line entity, there are two collections: line.lineStops and line.StopCollectionViaLinestops (read-only)

To get a list of related stops, I'm passing in the (previously saved with 'Refetch = true') line entity to a function which does the following:


public static void LoadLineStops(LineEntity line)
        {
            using (DataAccessAdapter adapter = new DataAccessAdapter(DBConnection))
            {
                adapter.FetchEntityCollection(line.Linestops, line.GetRelationInfoLinestops());
                adapter.FetchEntityCollection(line.StopCollectionViaLinestops, line.GetRelationInfoStopCollectionViaLinestops());
            }
        }

Both before and after running this code, although the number of linestops is correct ( 8 ) the StopCollectionViaLineStops contains 14 objects, which is wrong. I should have 8. cry

Do I have to clear this collection before trying to refresh it? I'd rather not reload the entire line object.

Thanks in advance.

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 03-Mar-2009 04:58:04   

Yes, you have to clear the collections before fetch them.

David Elizondo | LLBLGen Support Team
Meteor
User
Posts: 67
Joined: 06-Apr-2007
# Posted on: 03-Mar-2009 05:19:58   

What's the best way? Clear() doesn't work because it's read only.

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 03-Mar-2009 07:08:25   

You can try to fetch into new collections or set the DoNotPerformAddIfPresent property for each collection to true.

Meteor
User
Posts: 67
Joined: 06-Apr-2007
# Posted on: 03-Mar-2009 10:33:30   

Sorry Walaa, I don't understand.

What's happened here is that I've used the appropriate collection container (StopCollectionViaLineStops) to hold the original lot of related stops. Now after allowing the user to change that collection (by modifying Linestops), I'm trying to refresh the StopcollectionViaLineStops.

How does 'DoNotPerformAddIfPresent' help? I have read oodles of topics about that and it doesn't seem relevant at all.

What I need to do is to have a way to clear the collection and refetch it.

Is this not possible?

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 03-Mar-2009 11:03:34   

Sorry, I was a little bit confused. Would you please post a repro solution?

Meteor
User
Posts: 67
Joined: 06-Apr-2007
# Posted on: 03-Mar-2009 11:27:21   

No worries.

Can't post a repro due to NDA, but essentially, all I'm doing is binding a standard EntityCollection<LineEntity> to a DataGridView, using a Bindingsource. When they click on a row in the grid (to edit that line), I'm popping up a detail view of the line, with its associated stops and allowing them to change the stops and re-order them.

To get the line item to edit, I'm just using '(LineEntity)linebindingsource.Current' to get the line, and passing this to a form opened via 'form.ShowDialog()'. Back in the main form, I'm checking the DialogResult and if ok, I'm saving the EntityCollection that the DataGridView's bound to. Next time they edit that row, I'm hoping to grab the collection of stops (via the linestops relationship) and use it to show them the stops currently associated with this line. Unfortunately, it seems that once you populate that collection for a LineEntity, it stays there for life.

You can't clear it. You can't refetch it (believe me, I've tried). So your only option is to clear entire BindingSource.DataSource and refetch it after you've changed anything on any of the items. N'est'ce pas?

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 03-Mar-2009 11:36:45   

You can't clear it. You can't refetch it (believe me, I've tried). So your only option is to clear entire BindingSource.DataSource and refetch it after you've changed anything on any of the items. N'est'ce pas?

That's what's puzzeling me. Coz you should always be able to clear a related collection.

I've just tried the following and it's working fine (over Northwind): The code is for SelfServicing, but this should make no difference.

            PrefetchPath prefetch = new PrefetchPath(EntityType.CustomersEntity);
            prefetch.Add(CustomersEntity.PrefetchPathEmployeesCollectionViaOrders);
            CustomersCollection customers = new CustomersCollection();
            customers.GetMulti(null, prefetch);
            //customers[0].EmployeesCollectionViaOrders.Count = 5;
            customers[0].EmployeesCollectionViaOrders.Clear();
            //customers[0].EmployeesCollectionViaOrders.Count = 0;

So if's raising an exception, would you please post the exception text and stack trace.

I'm using adapter on 2.6 Final

Which runtime library build, exactly?

Meteor
User
Posts: 67
Joined: 06-Apr-2007
# Posted on: 03-Mar-2009 12:01:49   

I'm currently at home (because I'm in Australia and this is the only time I can catch you), so can't give you the exact error, but when I call:

line.StopsCollectionViaLinestops.Clear(), I get an error stating the collection is read-only.

As per my earlier code. If I try to fill the collection again, it doesn't work - the collection still contains too many items.

I'll post the stack trace and exact build tomorrow.

Meteor
User
Posts: 67
Joined: 06-Apr-2007
# Posted on: 03-Mar-2009 22:13:19   

Ok. Runtime Version is v2.0.50727


System.InvalidOperationException was unhandled by user code
  Message="This collection is read-only."
  Source="SD.LLBLGen.Pro.ORMSupportClasses.NET20"
  StackTrace:
       at SD.LLBLGen.Pro.ORMSupportClasses.CollectionCore`1.Clear()
       at TA.BLL.BusinessLayer.LoadLineStops(LineEntity line)
       at TA.frmEditLine.frmEditLine_Load(Object sender, EventArgs e) in C:\Version Control\TABackOffice\TADesktop\frmEditLine.cs:line 35
       at System.Windows.Forms.Form.OnLoad(EventArgs e)
       at System.Windows.Forms.Form.OnCreateControl()
       at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
       at System.Windows.Forms.Control.CreateControl()
       at System.Windows.Forms.Control.WmShowWindow(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
       at System.Windows.Forms.ContainerControl.WndProc(Message& m)
       at System.Windows.Forms.Form.WmShowWindow(Message& m)
       at System.Windows.Forms.Form.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

During execution of the following:


public static void LoadLineStops(LineEntity line)
        {
            using (DataAccessAdapter adapter = new DataAccessAdapter(DBConnection))
            {
                line.Linestops.Clear(); //Successful
                line.StopCollectionViaLinestops.Clear(); //Fails on this line
                adapter.FetchEntityCollection(line.Linestops, line.GetRelationInfoLinestops());
                adapter.FetchEntityCollection(line.StopCollectionViaLinestops, line.GetRelationInfoStopCollectionViaLinestops());
            }
        }

MTrinder
User
Posts: 1461
Joined: 08-Oct-2008
# Posted on: 03-Mar-2009 22:22:46   

That's a .NET runtime version rather than the LLBLGen runtime version

Please check this thread for guidance

Thanks

Matt

Meteor
User
Posts: 67
Joined: 06-Apr-2007
# Posted on: 03-Mar-2009 22:43:54   

2.6.9.116

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 04-Mar-2009 07:40:21   

Just to be sure: Are you using Context classes? (see this. http://llblgen.com/tinyforum/Messages.aspx?ThreadID=5467)

Also, if you could make a repro solution (nothing fancy nor confidential, just Northwind, that reproduces more or less your special scenario and have the same error) would save us some time to figure this out wink

David Elizondo | LLBLGen Support Team
Meteor
User
Posts: 67
Joined: 06-Apr-2007
# Posted on: 04-Mar-2009 10:02:43   

I'm not using context classes. I read a bit about them, but I'm trying to keep it simple. I mean, the whole reason we use tools like this is to save time and effort - isn't it?

Don't worry about it. I haven't really got time to send a repro solution with Northwind. I've read enough in the forums to realise that an m:n collection like StopCollectionViaLineStops is read-only. My only gripe is that it can't be cleared or re-fetched, or rather, if it is re-fetched, it isn't updated.

As a workaround, I've created a partial class called LineEntityExtensions which extends LineEntity, and added a Property called TempLineStops which can hold a collection of StopEntities.

I do think that this is a bug, though, Frans, albeit not a critical one.

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 04-Mar-2009 10:41:59   

I was wrong when I made the assumption that SelfServicing won't differ from Adapter in this issue.

You can clear the collection in SelfServicing but you can't in Adapter. The following Northwind repro has failed:

            EntityCollection<CustomersEntity> customers = new EntityCollection<CustomersEntity>();

            PrefetchPath2 prefetch = new PrefetchPath2(EntityType.CustomersEntity);
            prefetch.Add(CustomersEntity.PrefetchPathEmployeesCollectionViaOrders);

            using (DataAccessAdapter adapter = new DataAccessAdapter())
            {
                adapter.FetchEntityCollection(customers, null, prefetch);
            }
            customers[0].EmployeesCollectionViaOrders.Clear();

We'll investigate the options and get back to you.

Meteor
User
Posts: 67
Joined: 06-Apr-2007
# Posted on: 04-Mar-2009 11:14:27   

Walaa, I think that you'll also find that if you immediately then change the database so that the Employees collection returns fewer entities, then try to refetch the EmployeesCollectionViaOrders (using the same code you have provided) it won't reflect the changes.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39613
Joined: 17-Aug-2003
# Posted on: 04-Mar-2009 13:11:12   

Meteor wrote:

Walaa, I think that you'll also find that if you immediately then change the database so that the Employees collection returns fewer entities, then try to refetch the EmployeesCollectionViaOrders (using the same code you have provided) it won't reflect the changes.

What does 'refetch' mean in this case? refetch the data into the same entities? that's logical, you've to use a context. Though then still you indeed won't see the collections being cleared first

Not being able to clear a m:n collection is due to the fact it's set as ReadOnly. To work around that, you've to set the ReadOnly property to false first.

It's indeed a bit of a problem: the m:n collection is a view on the m:n related data but at a certain time, so right after the set is fetched, it could be different, but that's not reflected in the collection. It's not really solvable properly.

Frans Bouma | Lead developer LLBLGen Pro
Meteor
User
Posts: 67
Joined: 06-Apr-2007
# Posted on: 04-Mar-2009 22:10:38   

I think of the collection of 'EmployeesCollectionViaOrders' or 'StopCollectionViaLinestops' as being simply a holder for a snapshot of entities at a certain time, therefore, code like this


public static void LoadLineStops(LineEntity line)
        {
            using (DataAccessAdapter adapter = new DataAccessAdapter(DBConnection))
            {               
                adapter.FetchEntityCollection(line.StopCollectionViaLinestops, line.GetRelationInfoStopCollectionViaLinestops());
            }
        }

should just fill that collection with a snapshot collection of entities from the database. Unfortunately, it doesn't do that unless the collection is empty, which is only the case the first time you fill it.