Usage of customer.Orders.AddRange(ICollection<T>)

Posts   
 
    
sbense
User
Posts: 55
Joined: 24-Jul-2007
# Posted on: 13-Sep-2007 18:14:59   

I am confused as to how to add a range of entities to a related entity using the AddRange method. I'm using the Northwind database to illustrate the problem.

I don't understand how to add a range of order items to a customer entity, as this sample raises a cast error. I understand what a cast error is, but I don't know how to use the AddRange with a ICollection<T>. I've also tried a generic list - List<OrderEntity>.

How would an EntityCollection be cast to a ICollection<T>? This seems like an extra step. Why can't an EntityCollection of the same type be added?


//Get customer with CustomerId = 1000
CustomerEnity customer = new CustomerEntity(1000);

//Create an orders collection
EntityCollection<OrderEntity> orders = new EntityCollection<OrderEntity>();

//Add 2 empty orders - assume that the orders table has no required fields
orders.Add(new OrderEntity());
orders.Add(new OrderEntity());

//Add the orders
customer.Orders.AddRange(orders);

//This does not work as Customer.Orders is ReadOnly. 
//I would expect the assignment to happen internally to the AddRange method
customer.Orders = orders;


A simple for each on the orders collection works, but the AddRange should be the more elegant option.


foreach(IEntity2 order in orders)
     customer.Orders.Add(order);

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 14-Sep-2007 11:26:08   

Which version of the runtime libraries are you using?

sbense
User
Posts: 55
Joined: 24-Jul-2007
# Posted on: 14-Sep-2007 11:27:48   

Walaa wrote:

Which version of the runtime libraries are you using?

Version 2.0.0

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 14-Sep-2007 11:32:44   

That's not a runtime library version. Please check the following thread: http://www.llblgen.com/TinyForum/Messages.aspx?ThreadID=7725

sbense
User
Posts: 55
Joined: 24-Jul-2007
# Posted on: 14-Sep-2007 12:11:43   

Walaa wrote:

That's not a runtime library version. Please check the following thread: http://www.llblgen.com/TinyForum/Messages.aspx?ThreadID=7725

Sorry I looked at the assembly version, so the file version is 2.0.07.0611

Here is the stack trace and error exception, although these are showing details of my database schema and not Northwind.

Error and stacktrace

Error: Unable to cast object of type 'SLN.Focus.ADRegister.DAL.HelperClasses.EntityCollection1[SLN.Focus.ADRegister.DAL.EntityClasses.MyTblGroupModifyEntity]' to type 'System.Collections.Generic.ICollection1[SLN.Focus.ADRegister.DAL.EntityClasses.TblGroupModifyEntity]'.

Stacktrace: at FocusBLL.UIHelper.DocumentManager.CreateDocument(DocInfo context) in C:\projects\FOCUSi\trunk\Development\Focus\BLL\FocusBLL\EDMSManager.vb:line 552 at Focus.DAL.EDMSManager.DocumentManager.CreateDocument() in C:\projects\FOCUSi\trunk\Development\Test\Focus.Support.Adapter.Test\UnitTests\DAL.Test\EDMSManagerTests.cs:line 218

Actual code where the error occurs

 'Add ModifyGroups
mDocumentEntity.TblGroupModify.AddRange(Me.ModifyGroups)

where : 1:n relationship exists between DocumentEntity and GroupModify Me.Modify groups is an EntityCollection(Of ModifyGroupEntity)

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 14-Sep-2007 16:00:38   

I think you've ran into a co-variance issue.

I've tried your example:



        [Test]
        public void AddRangeTest()
        {
            CustomerEntity customer = new CustomerEntity();

            //Create an orders collection
            EntityCollection<OrderEntity> orders = new EntityCollection<OrderEntity>();

            //Add 2 empty orders - assume that the orders table has no required fields
            orders.Add(new OrderEntity());
            orders.Add(new OrderEntity());

            //Add the orders
            customer.Orders.AddRange(orders);
        }

this works.

What I think is the problem is that you use adapter two-class scenario and you tried to add a range of entities which are in the collection which had the SUPERtype for T to the collection which had the subtype of T.

This also doesn't work:


List<object> toAdd = new List<object>();
toAdd.Add("Foo");
toAdd.Add("Bar");
List<string> strings = new List<string>();
strings.AddRange(toAdd);

Because List<object> can't be converted to List<string>. Although string is a subtype of object, List<string> isn't related to List<object> in the same way.

So I think you defined Me.ModifyGroups as EntityCollection(Of TblGroupModifyEntity) but it should be EntityCollection(Of MyTblGroupModifyEntity)

Frans Bouma | Lead developer LLBLGen Pro
sbense
User
Posts: 55
Joined: 24-Jul-2007
# Posted on: 14-Sep-2007 18:01:07   

Otis wrote:

So I think you defined Me.ModifyGroups as EntityCollection(Of TblGroupModifyEntity) but it should be EntityCollection(Of MyTblGroupModifyEntity)

Thank you for spotting that. Spot on that was the mistake I made. Maybe I'm using the collections incorrectly so here is my code to clarify what I am doing.


Public ReadOnly Property ModifyGroups() As EntityCollection(Of MyTblGroupModifyEntity)
        Get
                If Me.mModifyGroups Is Nothing Then
                    mModifyGroups = New EntityCollection(Of MyTblGroupModifyEntity) _ 
                                                      (New MyTblGroupModifyEntityFactory())
                 End If
            Return (Me.mModifyGroups)
        End Get
End Property

Public Sub TestGroups()
    Dim mDocumentEntity as New MyTblDocumentEntity()

    'Test entry
    Me.ModifyGroups.Add(New RegisterEntity.MyTblGroupModifyEntity(100))

    'Add ModifyGroups
    mDocumentEntity.TblGroupModify.AddRange(Me.ModifyGroups)

End Sub

This entity "mDocumentEntity.TblGroupModify" is actually of type EntityCollection(Of TblGroupModify) which explains why it does not work. However I am now confused as to when to use the MyTbl.. and Tbl versions of the entities.

I suppose the question I need answering is why does mDocumentEntity which is of the supertype MyTblDocumentEntity not have a .MyTblGroupModify collection of the corresponding supertype?

Thanks for the help so far.

This works:


Public ReadOnly Property ModifyGroups() As EntityCollection(Of TblGroupModifyEntity)
        Get
                If Me.mModifyGroups Is Nothing Then
                    mModifyGroups = New EntityCollection(Of TblGroupModifyEntity) _ 
                                                     (New TblGroupModifyEntityFactory())
                 End If
            Return (Me.mModifyGroups)
        End Get
End Property

Public Sub TestGroups()
    Dim mDocumentEntity as New MyTblDocumentEntity()

    'Test entry
    Me.ModifyGroups.Add(New RegisterEntity.MyTblGroupModifyEntity(100))

    'Add ModifyGroups
    mDocumentEntity.TblGroupModify.AddRange(Me.ModifyGroups)

End Sub


Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 15-Sep-2007 12:01:04   

You use the 2-class scenario, so you should use the My* entities everywhere and not the other ones. That way the hierarchies are all of the correct types. simple_smile This is because of the following: MyCustomerEntity is subtype of CustomerEntity, and MyOrderEntity is subtype of OrderEntity. 'Orders' in MyCustomerEntity... has to hide Orders in CustomerEntity, because that is of type EntityCollection<OrderEntity>, not of type EntityCollection<MyOrderEntity> (as it is part of CustomerEntity), and List<string> isn't a subtype of List<object> simple_smile

Frans Bouma | Lead developer LLBLGen Pro
sbense
User
Posts: 55
Joined: 24-Jul-2007
# Posted on: 17-Sep-2007 10:57:40   

Otis wrote:

You use the 2-class scenario, so you should use the My* entities everywhere and not the other ones. That way the hierarchies are all of the correct types. simple_smile This is because of the following: MyCustomerEntity is subtype of CustomerEntity, and MyOrderEntity is subtype of OrderEntity. 'Orders' in MyCustomerEntity... has to hide Orders in CustomerEntity, because that is of type EntityCollection<OrderEntity>, not of type EntityCollection<MyOrderEntity> (as it is part of CustomerEntity), and List<string> isn't a subtype of List<object> simple_smile

Thank you for your response. I understand the usage now. Although I would like to use the MyTbl.. versions of the entities, it is clear that when adding to the MyTbl* entities to collections of type TblEntity that the AddRange method will only accept the Tbl collection.

As shown in the example below I can add MyTbl* entities to the related collection if I iterate across the IEntity2 entries of a MyTbl* collection, but I can't AddRange with a collection of different types - I understand that now.

This works

'Add a test entry
    Me.ModifyGroupLists.Add(New RegisterEntity.MyTblGroupModifyEntity())
    
    'Add range of EntityCollection(Of TblGroupModifyEntity)
    mDocumentEntity.TblGroupModify.AddRange(Me.ModifyGroups)

    'Add items from EntityCollection(Of MyTblGroupModifyEntity)
    For Each entity As IEntity2 In Me.ModifyGroupLists
        mDocumentEntity.TblGroupModify.Add(entity)
    Next

Where ModifyGroups is EntityCollection(Of TblGroupModifyEntity) ModifyGroupLists is EntityCollection(Of MyTblGroupModifyEntity) mDocumentEntity.TblGroupModify is EntityCollection(Of TblGroupModify)

but this does not work

'Add a test entry
    Me.ModifyGroupLists.Add(New RegisterEntity.MyTblGroupModifyEntity())
    
    'Can't do this!
    'Add range of EntityCollection(Of MyTblGroupModifyEntity)
    mDocumentEntity.TblGroupModify.AddRange(Me.ModifyGroupLists)

    'This does not work either 
    'Add items from EntityCollection(Of MyTblGroupModifyEntity)
    For Each entity As MyTblGroupModifyEntity In Me.ModifyGroupLists
        mDocumentEntity.TblGroupModify.Add(entity)
    Next

My final question is shouldn't the AddRange simply iterate the interface entities to achieve the same result?

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 17-Sep-2007 12:36:44   

My final question is shouldn't the AddRange simply iterate the interface entities to achieve the same result?

As far as I know, Generic types are typesafe to the type they are bound to. i.e. ICollection<> of one type can not be casted to a ICollection<> of a derived or base type.

sbense
User
Posts: 55
Joined: 24-Jul-2007
# Posted on: 17-Sep-2007 18:10:20   

Thank you for all the feedback and input here. This thread is now closed.