EntityFactoryToUse on related collection

Posts   
 
    
zaad
User
Posts: 19
Joined: 13-Sep-2005
# Posted on: 05-Oct-2005 10:12:03   

Hello,

In Selfservicing, how can I set the entityfactorytouse for a related collection?

I have a collection of orders with 1:m related collection of orderitems.

I'm using a prefetch path on the getMulti() of the orderscollection to get the related orderitems. I want these orderitems to have a different (inherited) entityfactory.

I saw that IPrefetchPath2 supports this, but that Adapter, right?

Greetz,

Zaad

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 05-Oct-2005 11:04:09   

It's not supported in the add method but you can set the EntityFactoryToUse on the RetrievalCollection of the PrefetchPathElement returned by Add() simple_smile

Frans Bouma | Lead developer LLBLGen Pro
zaad
User
Posts: 19
Joined: 13-Sep-2005
# Posted on: 05-Oct-2005 12:16:37   

Haven't seen that yet. Tried it:

                //stel een prefetch path in
                IPrefetchPath prefetchPathOpdracht = new PrefetchPath((int)EntityType.OpdrachtEntity);
                IPrefetchPathElement pfpeOpdrachtRegel = OpdrachtEntity.PrefetchPathOpdrachtRegel;
                pfpeOpdrachtRegel.RetrievalCollection.EntityFactoryToUse = new Inova.FactoryClasses.BestellingRegelEntityFactory();
                //stel een sortclause voor de opdrachtregels in
                ISortExpression sorterOpdrachtRegels = new SortExpression(SortClauseFactory.Create(OpdrachtRegelFieldIndex.Volgnr, SortOperator.Ascending));
                //zet opdrachtregelelement in prefetchpath
                prefetchPathOpdracht.Add(pfpeOpdrachtRegel, 0, null, null, sorterOpdrachtRegels);
                //stel een sortclause voor de opdracht in
                ISortExpression sorterOpdracht = new SortExpression(SortClauseFactory.Create(OpdrachtFieldIndex.OrderNr, SortOperator.Descending));
                //roep getmulti aan
                opdrachtCollection.GetMulti(m_filter, 0, sorterOpdracht, relationsToUse, prefetchPathOpdracht);

m_filter en relationsToUse are set earlier in the code.

The collections are bounded to datagrids (or visaversa).

When I run the code, the first master-record has duplicate child-records and the rest of the master-record does not. confused

If I replace:

new Inova.FactoryClasses.BestellingRegelEntityFactory();

with:

new Inova.FactoryClasses.OpdrachtRegelEntityFactory();

which is the base entityfactory of BestellingRegelEntityFactory, all is OK.

Could it be an error in the derived entityfactory?


    /// <summary>
    /// Factory to create new, empty BestellingRegelEntity objects.
    /// </summary>
    [Serializable]
    public class BestellingRegelEntityFactory : OpdrachtRegelEntityFactory
    {
        /// <summary>
        /// Creates a new, empty BestellingEntity object.
        /// </summary>
        /// <returns>A new, empty BestellingEntity object.</returns>
        public override IEntity Create()
        {
            IEntity toReturn = new BestellingRegelEntity();

            return toReturn;
        }
    }

Please help!

Zaad

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 05-Oct-2005 13:28:20   

change: IEntity toReturn = new BestellingRegelEntity(); into: IEntity toReturn = new BestellingRegelEntity(new PropertyDescriptorFactory(), this);

I'm not sure it will be the problem, as I don't know how BestellingenRegelEntity is constructed (e.g.: why you need the factory, is it created as a derived entity by hand?)

Frans Bouma | Lead developer LLBLGen Pro
zaad
User
Posts: 19
Joined: 13-Sep-2005
# Posted on: 05-Oct-2005 15:25:57   

It didn't help.

Let me explain why I need the factory.

I have a base class Opdracht from which Bestelling is derived with some additional properties and methods. In a certain screen I have a master-grid bound to an opdrachtCollection and a detailgrid bound to its related OpdrachtRegelCollection.

I want to load the OpdrachtCollection and OpdrachtRegelCollection as Bestelling and BestellingRegels because when a single BestelllingRegel needs to be changed I can't 'up'-cast from Opdrachtregel to BestellingRegel.

Thus, I want to tell the collection to use the BestellingRegel-factory.

Maybe this is a wrong approach? confused

Don't hesitate to tell me when you think it is.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 06-Oct-2005 16:50:36   

Ok, the prefetch path collection factory you set is needed to read the objects into Bestellingen entities. If you want to tell teh collection they'll be stored in to use Bestellingen type as well, you have to set that collection's factory to BestellingenEntityFactory as well, for example after the prefetch path call, as otherwise you'll trigger lazy loading.

Frans Bouma | Lead developer LLBLGen Pro
zaad
User
Posts: 19
Joined: 13-Sep-2005
# Posted on: 18-Oct-2005 21:16:47   

I found out that after the getMulti() of the BestellingCollection the first item in BestellingCollection has instances of BestellingRegel as well as instances of OpdrachtRegel. (duplicate data)

I seems that only for the first Bestelling-item there is a fetch of the base OpdrachtRegel-entity as well as the derived BestellingRegel-entity.

A workaround is: a GetMultiOpdrachtRegel(true) on the first Bestelling-item after the getMulti();

Why does the first item in the collection use the OpdrachtRegelEntity-factory as well as the BestellingRegelEntity-factory?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 19-Oct-2005 14:11:52   

when you do: myOrder.Customer = myCustomer; it will do under the hood: myCustomer.Orders.Add(myOrder);

so myOrder will then be present in myCustomer.Orders.

If you then do: OrderCollection orders = myCustomer.Orders;

the orders are fetched, and because myOrder is already there, it's not added twice. The object fetcher does a compare on PK, using a hashcode calculated from that PK. So I'm a bit surprised the entity ends up twice. Is opdrachtentity.Equals(bestellingentity) true, for the entities which are the same?

Frans Bouma | Lead developer LLBLGen Pro
zaad
User
Posts: 19
Joined: 13-Sep-2005
# Posted on: 19-Oct-2005 20:45:12   

One is of type OpdrachtRegelEntity and the other of type BestellingRegelEntity. They have the same PK value (OpdrRegId), however opdrRegel.Equals(bestRegel) returns FALSE. confused

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 20-Oct-2005 09:49:10   

zaad wrote:

One is of type OpdrachtRegelEntity and the other of type BestellingRegelEntity. They have the same PK value (OpdrRegId), however opdrRegel.Equals(bestRegel) returns FALSE. confused

Ah, I see what's the problem.

Equals does a direct GetType() compare, and if they fail, they're not equal. Which makes sense, because the types aren't the same. So this means the Add() function doesn't find the dupe. What I do find is that the fetch routine doesn't find the duplicate either. I'll check it out.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 24-Oct-2005 10:55:53   

Ok, here's the problem: the object fetch logic does this: it first creates a hashtable (one key per hashvalue, created from the PK of each entity) which contains the duplicates of the collection to fetch entities into.

For duplicate hashvalues (which can happen, a hashvalue is an int afterall) it creates an arraylist with all the objects with the same hashvalue, normal hashbucket behavior.

Ok, so it first stores opdracht.

Then it fetches bestellingen into that collection. At one point, the same ENTITY (i.e.: data) is read as the opdracht entity already there. Hashvalue is the same (same PK), so the logic grabs the bucket and checks which entity is the same. It does that using indexof (which uses equals). None shows up. This is logical, because opdracht isn't a bestelling. Bestelling is an opdracht, but opdracht can also be something else.

Ok, so it determines that bestelling is not in the collection yet and stores it. Dupe.

I've thought about this and decided not to fix it. The main point is: are Opdracht and Bestelling equal if they represent the same entity, though opdracht is holding just a part of the whole entity (which is of a subtype of opdracht: bestelling) ? I think they shouldn't be considered equal.

In 1.0.2005.1, which is hopefully released later today, you can map supertype/subtypes which will solve this problem for you, but also there you can have the same problem. If it confuses too much people I'll probably change this semantical interpretation, (it's philosophical: when are things equal? wink ) but for now I keep it as is.

Frans Bouma | Lead developer LLBLGen Pro