This project is read-only.
2

Resolved

ConcurrentHashtable : Custom Comparer Madness!

description

Hi Thomas -
 
I would really appreciate a fix for this. We've put several days into this issue.
 

Background:

We are using Obtics with LLBLGen Pro, one of the strongest ORMs for .NET (also from the Netherlands). All our Calculations are performed server-side in real-time (not on the client as with Silverlight). Thus - ConcurrentHashtable is EXTREMELY important so users are isolated from eachother's Calculations on the server.
 

Problem:

Obtics is not always using the ObticsEqualityComparerAttribute to do comparisons. Our breakpoints in our custom Comparer are firing, so we know we are hooked in correctly. However, Obtics is still calling .Equals or .GetHashCode on the objects themselves - instead of our Comparer. This is causing major problems.
 
Unwanted Side Effects, either:
1.) With Custom Comparer: Only calculations in the first screen work, no calculations in any successive screens or dialogs will function.
2.) Without Custom Comparer: All Calculations for an Entity are shared across all user sessions!! If User #1 views Entity A1, and another User #2 views Entity A2... User #1's calculations are displayed on User #2's screen.
 

LLBLGen Pro

.Equals() method is based solely on PrimaryKeys.
.GetHashCode() method is based solely on all matching field values.
 
Using the methods above, cloning an Entity will result in the clone & original being "equal". Also, fetching the same entity twice from the DB... both instances are considered "equal" in the LLBLGen world. Thus, Obtics will not listen to a cloned entity or a re-fetched entity - because Obtics thinks it is already listening to it, when really it's only listening to the first entity.
 
This is severely limiting & does not allow for multiple instances of an Entity to be calculated independently on separate screens.
 
We are using deep cloning extensively for child screens / dialog windows where Calculations must be made. Thus - the main screen's Calculations must be kept /completely/ separate from the child screen's Calculations. For our cloned entities to Calculate independently of the original entities, we need to enforce ReferenceEquals() comparison in Obtics. Anything less will result in disastrous cross-screen & cross-session calculations. As you can imagine - horror stories for both our users and the development team.
 
After days of work, we have narrowed it down to a simple unit test, which I am more than happy to provide you with.
 
Also, We do not create any anonymous types in our Expressions, as you have mentioned in other posts. We have read up on:

Custom Comparer - Used to keep each object instance separate, so calculations are able to fire separately on two cloned entities:

public class RyansObticsEntityComparer : IEqualityComparer<CommonEntityBase>
{
public bool Equals(CommonEntityBase x, CommonEntityBase y)
{
    // Require Same Instance
    return ReferenceEquals(x, y);
}
 
public int GetHashCode(CommonEntityBase obj)
{
    // Return Unique Instance Guid
    byte[] guidBytes = obj.UniqueInstanceID.ToByteArray();
    return BitConverter.ToInt32(guidBytes, 0);
}
}
 
[Obtics.ObticsEqualityComparer(typeof(RyansObticsEntityComparer))]
public class CommonEntityBase
{ ...

file attachments

comments

Throb wrote Dec 15, 2009 at 9:15 AM

Hi Ryan,

When Obtics manipulates your naked objects it should use the comparer specified with the ObticsEqualityComparer always. If it doesn't it means there is a bug. Could you provide more details about the circumstanses in which Obtics gets it wrong? Could you upload your unit test?

If there is a bug it needs to be fixed; but is it not possible for LLBLGen to take the session/transaction/other context into account when comparing entities? I have a tendensy to see it as a shortcomming that it declares two entities equal when in fact they are not.

Regards,

Thomas.

rdhatch wrote Dec 15, 2009 at 10:21 PM

Hi Thomas -

Thank you very much for taking a look at this. Please find the attached .zip file. These 3 tests cover everything we need.

Again, Thank you very much!

Ryan

wrote Dec 15, 2009 at 10:22 PM

wrote Dec 16, 2009 at 9:07 PM

Associated with changeset 32502.

wrote Dec 16, 2009 at 9:07 PM

Throb wrote Dec 16, 2009 at 9:15 PM

Hi Ryan,

The fault was caused by the ComponentModel.PropertyDescriptor class. It uses a (static) dictionary to store registrations for ChangeEvents (PropertyDescriptor.AddValueChanged). This component naturaly doesn't take ObticsEqualityComparerAttribute into account and since the default equality comparer for the Entities is not well behaved the component fails.

Code has been changed so that if an ObticsEqualityComparerAttribute has been specified on a type it will not use PropertyDescriptor for change notifications. This in turn means that the only property change notification mechanism for such types can be INotifyPropertyChanged.

I have uploaded an Obtics.dll with the patch built in.

Tx for reporting the issue,

Thomas.

wrote Dec 16, 2009 at 9:15 PM

rdhatch wrote Dec 16, 2009 at 9:53 PM

All tests pass successfully. Thank you very much, Thomas!

You are greatly appreciated!

Ryan D. Hatch

wrote Feb 14, 2013 at 2:41 AM

wrote May 16, 2013 at 5:55 AM

wrote May 16, 2013 at 5:55 AM

wrote Jun 14, 2013 at 8:53 AM