Unit of work issue

Posts   
 
    
Posts: 93
Joined: 13-Feb-2008
# Posted on: 20-Jun-2008 18:23:34   

static void Main(string[] args)
        {
            UnitOfWork2 uow = new UnitOfWork2();

            PaymentRequestEntity target = new PaymentRequestEntity(12345);
            Fetch(target);

            uow.AddForSave(target, null, false, false);
            uow.AddForSave(target.PaymentRequestDetails[0], null, false, false);

            target.PaymentRequestDetails[0].ClaimantId = Guid.NewGuid().ToString().Substring(0, 20);

            using (DataAccessAdapter adapter = new DataAccessAdapter())
            {
                uow.Commit(adapter, true);
            }

            Fetch(target);

            try
            {
                Console.WriteLine(target.PaymentRequestDetails[0].ClaimantId);              
            }
            catch( Exception e)         
            {
                Console.WriteLine(e.Message);   
            }

            Console.ReadLine();
        }

        static void Fetch(PaymentRequestEntity e)
        {
            using (DataAccessAdapter adapter = new DataAccessAdapter())
            {
                PrefetchPath2 prefetch = new PrefetchPath2(EntityType.PaymentRequestEntity);
                prefetch.Add(PaymentRequestEntity.PrefetchPathPaymentRequestDetails);
                adapter.FetchEntity(e, prefetch);
            }
        }

output is always entity out of synch exception. I don't want to do a recursive save on the target entity, i want more fine grained control. Any ideas on why the second fetch fails to re-synch the related entity?

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 21-Jun-2008 04:47:36   

Hi Becker,

OutOfSync is about refetching not about syncing between entities.

What field are you updating (a pk field, a fk to PaymentRequestEntity field, etc)? (please post the two tables structure (pk's, fk's).

David Elizondo | LLBLGen Support Team
Posts: 93
Joined: 13-Feb-2008
# Posted on: 23-Jun-2008 19:30:00   

Yeah I know what OutOfSync tells ya. The issue is that the second fetch does not "refetch" the "changed" associated object even though the prefetch path is there. Actually the sql pulls back the row but it isn't mapped/projected onto the object thus re-sync'ing the object. So subsequent access to the changed object's properties result in the OutOfSync exception.

I'm basically trying to avoid refetching via the uow since I know i have to refetch the whole object graph anyway.

The table structure is a simple 1:m relationship between paymentrequest and paymentrequestdetail

arschr
User
Posts: 893
Joined: 14-Dec-2003
# Posted on: 23-Jun-2008 20:13:04   

I wonder if using a context would solve your issue?

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 24-Jun-2008 06:33:13   

becker-samm wrote:

try
{
     Console.WriteLine(target.PaymentRequestDetail.ClaimantId);             
}

Did you mean target.PaymentRequestDetails[0].ClaimantId ??

becker-samm wrote:

So subsequent access to the changed object's properties result in the OutOfSync exception.

Please post the exception message and stack trace.

David Elizondo | LLBLGen Support Team
Posts: 93
Joined: 13-Feb-2008
# Posted on: 24-Jun-2008 15:05:46   

Yes that property simply points to the first object in the collection...I went ahead and updated the code sample just to avoid any confusion. Here is the stack trace


SD.LLBLGen.Pro.ORMSupportClasses.ORMEntityOutOfSyncException: The entity is out
of sync with its data in the database. Refetch this entity before using this in-
memory instance.
   at SD.LLBLGen.Pro.ORMSupportClasses.EntityBase2.GetValue(Int32 fieldIndex, Bo
olean returnDefaultIfNull)
   at Core.PaymentProcessor.Objects.EntityClasses.PaymentRequestDetailEntity.get
_ClaimantId() in C:\Projects\Core\Core.PaymentProcessor\Core.PaymentProcessor.Ob
jects\DatabaseGeneric\EntityClasses\PaymentRequestDetailEntity.cs:line 1319
   at UnitOfWorkStudy.Program.Main(String[] args) in C:\Projects\Core\UnitOfWork
Study\UnitOfWorkStudy\Program.cs:line 36

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 25-Jun-2008 11:56:32   

In the fetch method, please try to clear the target.PaymentRequestDetails collection first.

Posts: 93
Joined: 13-Feb-2008
# Posted on: 27-Jun-2008 22:05:21   

Ok, that works for the details collection. But it doesn't fix the issue when you have objects related to the details object as well. They simply aren't re-synched.

I'm having the same type of issue doing the following:

Load an object graph and exclude a majority of the fields via fetch and prefetchpath excludeincludefieldlists.

At some later time, refetch the entity with the same prefetch path but without the excludeincludefieldlists and the related entities are not re-fetched.

I just uploaded a code sample...the sql is correct for both fetches (exclude/included fields) but the second fetch does not map the previously excluded fields on to the current instance(s).

Attachments
Filename File size Added on Approval
Program.cs 16,790 27-Jun-2008 22:20.48 Approved
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39613
Joined: 17-Aug-2003
# Posted on: 28-Jun-2008 10:35:56   

The point is this: - if you want to have entities refetched after save, or have them being MARKED as saved after save, you either have to specify that they've to be refetched after save (which is a boolean flag on the AddForSave method, you pass false for that flag now), or you have to set the global flag that the framework should mark entities as fetched again after a save happens: See documentation link

  • if you want to fetch them manually, you have to realize that you're fetching new instances in the same containers at this point. To avoid that, so to fetch data into the same objects, use a context for the fetch: assign the target entity to a Context instance and the fetch will fetch the data into the same entities again.

I'd opt for refetching them by setting the flag on the AddForSave.

Frans Bouma | Lead developer LLBLGen Pro
Posts: 93
Joined: 13-Feb-2008
# Posted on: 30-Jun-2008 15:20:04   

Did you have a chance to look at the attached code? There is no saving going on there just a fetch with prefetches and excludeincludefield lists. Are you saying that in order to hydrate the object graph with the previously excluded fields you must use a context?

I'm a little confused by:

...you have to realize that you're fetching new instances...

The adapter.fetchentity method takes an entity as a parameter, and if i'm following the orm source code correctly fetching simply blasts the entity's fields with a set of fields populated from the database. In this scenario the reference is the same but the fields are changed. Is this not true for "re-fetching" with prefetch paths?

I think this is an important concept for me to get so can you elaborate on this a little bit?

Posts: 93
Joined: 13-Feb-2008
# Posted on: 30-Jun-2008 17:16:32   

So I followed the source code a bit further and I think I finally understand what the heck is going on here. (Please validate simple_smile )

The fetch (re-fetch) process for prefetch paths doesn't concern itself with whether the related objects exist. It relies on a "context" to supply the entities (existing references or new instances) to operate on. e.g If you don't supply a context then the fetch process will not use the existing related entities it will replace the reference in a m:1 and add duplicate entities (albeit correctly fetched) to 1:m collections.

Where runtime observation can get tricky is that any m:1 relationship "appears" to have had its fields updated but in reality it has actually been replaced by a new instance. For 1:m relationships the pitfall is in not noticing that the collection has doubled in size with 1/2 of the duplicated collection items hydrated according to the latest prefetch path.

Thanks for the help and I can chalk this one up as having a better understanding of the LLBLGen framework.

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 30-Jun-2008 17:51:15   

You got it right.