Problem when merging a linked entity collection with context object

Posts   
 
    
TomV
User
Posts: 76
Joined: 31-Jan-2008
# Posted on: 30-Jun-2008 14:33:05   

Hi

I'll try to subscribe the situation as good as possible.

**DB: ** Department -- Description -- DescriptionValues -- Languages The above database design gives us the possibility for administrators to translate the description of an department per language. The normal user logged on to our application will only see the description in his language.

Information: When an entity is saved in our client application, this entitytype and it's PK value is send to a server which broadcasts this to all active client applications. When for example user A adds a new department, the client application of user B will get notified of this. When user B was also using a grid which shows departments, the newly added department of user A will be added automatically. For deletes the entity on user B his departments form will be removed. Now I have a problem for updates for linked entities.

Each department has a code and a description. The code is unique and the description is stored in some linked tables so the description is language independant. When user A changes the description of an department, this is send via the server to user B it's client application. I try to find if the department is found in the collection with departments. If so, I fetch the changed description record (= DescriptionValueEntity). This is correctly fetched from the database. I then want to merge this with the existing entity available in my general context.


            List<int> indices = Entities.FindMatches(DepartmentFields.DescriptionId == pInfo.DescriptionId);
            if (indices.Count == 1)
            {
               DescriptionValueEntity newDescription = new DescriptionValueEntity(pInfo.Id);
               Main.DataServer.FetchEntity(newDescription);

               ISupportsDescriptionTranslation sup = Entities[indices[0]] as ISupportsDescriptionTranslation;
               List<int> tmp = sup.Description.DescriptionValues.FindMatches(DescriptionValueFields.Id == pInfo.Id);
               if (tmp.Count == 1)
                  sup.Description.DescriptionValues[tmp[0]] = (DescriptionValueEntity)Main.Context.Get(newDescription);
            }

Problem: Now the problem is with the following line of code


sup.Description.DescriptionValues[tmp[0]] = (DescriptionValueEntity)Main.Context.Get(newDescription);

Before I execute this line of code the DescriptionValues collection contains 4 records (dutch, french, english and polish). From the moment the above line of code is executed, and I want to merge the entity from my context with the entity fetched from the database, that particular entity is removed from my collection and the DescriptionValues collection only contains 3 records any more?

Can you please tell me why things behave like this?

Further I want to state that updates for core entity properties work just fine. So when user A changes the Code of the department (stored in the departmentEntity itself) the entities are nicely merged, and the screen of user B gets updated...

Kind regards, TomV

TomV
User
Posts: 76
Joined: 31-Jan-2008
# Posted on: 30-Jun-2008 16:15:10   

Hi,

What I just remembered. Those signals from the server are broadcasted by .NET Remoting. So they arrive at the client on another thread. So it might be linked to the fact that I'm using Context on multiple (2) threads.

I think I remeber reading something about this. So maybe this behavior is caused by a thread problem. How could I solve this? Use a lock for the call to Context on another thread?

Kind regards, TomV

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 01-Jul-2008 12:02:08   

If you store the result of: (DescriptionValueEntity)Main.Context.Get(newDescription); into a variable, what value does it have? I think it sees a duplicate.

Also, context.Get(entity) updates values in an existing entity. So if the entity at the location tmp[0] is already in the context, you don't have to set it again, simply the above line will do.

Contexts can't be used cross-thread. You should use them in the thread where the data is located as well, as it's about uniquing: the object is unique in a semantical context. Having two threads working with the same OBJECT gives a problem: both threads can alter things the other thread didn't expect.

Frans Bouma | Lead developer LLBLGen Pro
TomV
User
Posts: 76
Joined: 31-Jan-2008
# Posted on: 01-Jul-2008 12:57:44   

Thanks Otis!

Once again your explanation solved my problem. smile I tried to merge the newly fetched entity into my existing object, which was indeed already present in my Context.

The only reason I work with a separate thread with the Context is because the alerts from the server that an entity has changed by another user arrive on a different thread. When this happens I want to refetch the changed entity and update my context object. So more won't happen on that other thread. Is this "safe" or should I better use "lock(Context)" whenever I access my context, on both threads?

Kind regards, TomV

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 02-Jul-2008 10:51:26   

TomV wrote:

Thanks Otis!

Once again your explanation solved my problem. smile I tried to merge the newly fetched entity into my existing object, which was indeed already present in my Context.

The only reason I work with a separate thread with the Context is because the alerts from the server that an entity has changed by another user arrive on a different thread. When this happens I want to refetch the changed entity and update my context object. So more won't happen on that other thread. Is this "safe" or should I better use "lock(Context)" whenever I access my context, on both threads?

Kind regards, TomV

Best thing you can do is to use some form of thread communication, which is a generic problem and is discussed in depth in the MSDN and elsewhere on the net wink . The thing you should look at is that you have two threads: A and B. A contains / owns the context and the entities/graph. B is used for obtaining new data. You then should pass what B receives over to A and A then handles it further (using it to update entities via the context for example simple_smile )

Frans Bouma | Lead developer LLBLGen Pro
TomV
User
Posts: 76
Joined: 31-Jan-2008
# Posted on: 02-Jul-2008 10:53:13   

Thanks Otis. I will search the net to solve this problem.

The Context is a really nice concept!

Kind regards, TomV