OpenAccess ORM version
|
2011.2.908.1
|
.NET version |
3.5+ |
Visual Studio version |
2010
|
Programming language |
VB/C#
|
PROJECT DESCRIPTION
Sometimes when OA entities are disconnected (for example, due to loading from different domain contexts or from stored procedures or due to the use of a caching or storage mechanism), two copies of the same entity will not return true from a call to object.equals. We can fix this problem by implementing IEquatable and using
ObjectKeys.
You can do this in one of a few ways. The attached example builds on my
other example that creates a common base class for all entities using code generation templates. You can alternatively manually create the base class and create partial class definitions for all of your entities and add the inheritance on each entity. The other option is to create a helper class that implements IEqualityComparer<T> or IEqualityComparer and use this whenever you need an ObjectKey-based equality comparison.
In order to implement the IEquatable<T> interface and override the base equals and GetHashCode functions, all you need to add is the following code to your base entities class (I'm assuming your base class is called EntitiesBase - change this as needed):
C#:
using
System;
using
Telerik.OpenAccess;
using
Telerik.OpenAccess.SPI.dataobjects;
namespace
SofiaCarRental
{
public
partial
class
EntitiesBase : IEquatable<EntitiesBase>
{
bool
System.IEquatable<EntitiesBase>.Equals(EntitiesBase other)
{
if
(ReferenceEquals(
this
, other))
{
return
true
;
}
if
(other ==
null
)
{
return
false
;
}
if
(Database.GetContext(
this
) !=
null
&& Database.GetContext(other) !=
null
)
{
object
myKey = ObjectKey.CreateWithVersion(
this
);
object
otherKey = ObjectKey.CreateWithVersion(other);
return
myKey.Equals(otherKey);
}
else
{
return
base
.Equals(other);
}
}
public
override
bool
Equals(
object
obj)
{
if
(ReferenceEquals(
this
, obj))
{
return
true
;
}
if
(obj ==
null
)
{
return
false
;
}
object
pcObj = obj
as
PersistenceCapable;
if
(pcObj !=
null
)
{
if
(Database.GetContext(
this
) !=
null
&& Database.GetContext(pcObj) !=
null
)
{
object
myKey = ObjectKey.CreateWithVersion(
this
);
object
otherKey = ObjectKey.CreateWithVersion(pcObj);
return
myKey.Equals(otherKey);
}
}
//otherwise, use base implementation
return
base
.Equals(obj);
}
public
override
int
GetHashCode()
{
if
(Database.GetContext(
this
) !=
null
)
{
object
myKey = ObjectKey.CreateWithVersion(
this
);
return
myKey.GetHashCode();
}
else
{
return
base
.GetHashCode();
}
}
}
}
VB:
Imports
Telerik.OpenAccess
Imports
Telerik.OpenAccess.SPI.dataobjects
Partial
Public
Class
EntitiesBase
Implements
IEquatable(Of EntitiesBase)
Public
Function
Equals1(other
As
EntitiesBase)
As
Boolean
Implements
System.IEquatable(Of EntitiesBase).Equals
If
ReferenceEquals(
Me
, other)
Then
Return
True
End
If
If
other
Is
Nothing
Then
Return
False
End
If
If
Database.GetContext(
Me
) IsNot
Nothing
AndAlso
Database.GetContext(other) IsNot
Nothing
Then
Dim
myKey = ObjectKey.CreateWithVersion(
Me
)
Dim
otherKey = ObjectKey.CreateWithVersion(other)
Return
myKey.Equals(otherKey)
Else
Return
MyBase
.Equals(other)
End
If
End
Function
Public
Overrides
Function
Equals(obj
As
Object
)
As
Boolean
If
ReferenceEquals(
Me
, obj)
Then
Return
True
End
If
If
obj
Is
Nothing
Then
Return
False
End
If
Dim
pcObj = TryCast(obj, PersistenceCapable)
If
pcObj IsNot
Nothing
Then
If
Database.GetContext(
Me
) IsNot
Nothing
AndAlso
Database.GetContext(pcObj) IsNot
Nothing
Then
Dim
myKey = ObjectKey.CreateWithVersion(
Me
)
Dim
otherKey = ObjectKey.CreateWithVersion(pcObj)
Return
myKey.Equals(otherKey)
End
If
End
If
'otherwise, use base implementation
Return
MyBase
.Equals(obj)
End
Function
Public
Overrides
Function
GetHashCode()
As
Integer
If
Database.GetContext(
Me
) IsNot
Nothing
Then
Dim
myKey = ObjectKey.CreateWithVersion(
Me
)
Return
myKey.GetHashCode()
Else
Return
MyBase
.GetHashCode()
End
If
End
Function
End
Class
In implementation using IEqualityComparer<T> or IEqualityComparer would be very similar to the System.IEquatable<EntitiesBase>.Equals and Equals() definitions, respectively.
Please note that if you are using my
common base class example, do not put this code in the EntitiesBase.generated.[cs/vb] file or it will be overwritten. Also, as with the common base class example, be aware
that you will need to update the location of the code generation template and the RLINQ file before using the sample. To do this, open the domain model with an XML editor, find the following XML paths and update the node values (representing directories and files) to match your local ones:
DomainModel \ ModelSettings \ CodeGenerationSettings \ OutputPath - the project folder
DomainModel \ ModelSettings \ CodeGenerationSettings \ CustomTemplateFileName - location of the DefaultTemplate[Language].tt file
DomainModel \ ModelSettings \ SchemaUpdateSetting \ DeploymentDirectory - the project folder
The example solution also includes a console application the demonstrates the difference between the base object.equals and the ObjectKey based implementation.
Hope this helps.