The project I am working on requires data in our system to be synchronized with that of another (the other system is quite popular which is why synchronization is so importa
Well, I've at least figured out a solution to my problem, but not why. My solution was to create a new type that encompassed the properties I was using as the composite id:
public class CompositeIdType
{
public virtual long AssignedId { get; set; }
public virtual long GeneratedId { get; set; }
public override bool Equals(object obj)
{
return Equals(obj as CompositeIdType);
}
private bool Equals(CompositeIdType other)
{
if (ReferenceEquals(this, other)) return true;
if (ReferenceEquals(null, other)) return false;
return AssignedId == other.AssignedId &&
GeneratedId == other.GeneratedId;
}
public override int GetHashCode()
{
unchecked
{
int hash = GetType().GetHashCode();
hash = (hash * 31) ^ AssignedId.GetHashCode();
hash = (hash * 31) ^ GeneratedId.GetHashCode();
return hash;
}
}
}
Then, substitute the properties in ParentType for a reference to this new type:
public class ParentType
{
public virtual CompositeIdType Key { get; set; }
public virtual string SomeField { get; set; }
}
With those changes, the new mapping would be:
public class ParentMap : ClassMap
{
public ParentMap()
{
Table("STANDARDTASKITEM");
CompositeId(x => x.Key)
.KeyProperty(x => x.AssignedId, "STANDARDTASK")
.KeyProperty(x => x.GeneratedId, "STANDARDTASKITEM");
Map(x => x.SomeField, "DESCRIPTION");
Not.LazyLoad();
}
}
After all these changes are made, Merge works even when Get is called prior to the Merge call. My best bet is the non-generic form of CompositeId is not doing something correctly or that the mapping it is making is not working well with NH when you call Merge on an entity that uses it (I'd like to go into the source of FNH to fix it if that is the case but I've already spent too much time figuring out how to bypass this problem).
This is all well and good but this would require me to create a new type for each entity I am mapping, or at least a new type for an id with a different number of keys (ie a type with 2 keys, a type with 3 keys, etc.).
To avoid this, I can hack it so that you add a reference of the same type you are mapping and set the reference to this in the constructor:
public class ParentType
{
public ParentType()
{
Key = this;
}
public virtual ParentType Key { get; set; }
public virtual long AssignedId { get; set; }
public virtual long GeneratedId { get; set; }
public virtual string SomeField { get; set; }
public override bool Equals(object obj)
{
return Equals(obj as ParentType);
}
private bool Equals(ParentType other)
{
if (ReferenceEquals(this, other)) return true;
if (ReferenceEquals(null, other)) return false;
return AssignedId == other.AssignedId &&
GeneratedId == other.GeneratedId;
}
public override int GetHashCode()
{
unchecked
{
int hash = GetType().GetHashCode();
hash = (hash * 31) ^ AssignedId.GetHashCode();
hash = (hash * 31) ^ GeneratedId.GetHashCode();
return hash;
}
}
}
Then the mapping would be:
public class ParentMap : ClassMap
{
public ParentMap()
{
Table("STANDARDTASKITEM");
CompositeId(x => x.Key)
.KeyProperty(x => x.AssignedId, "STANDARDTASK")
.KeyProperty(x => x.GeneratedId, "STANDARDTASKITEM");
Map(x => x.SomeField, "DESCRIPTION");
Not.LazyLoad();
}
}
I have tested this for updating and inserting using Merge with Get getting called prior to the merge and surprisingly IT WORKS. I'm still on the fence on which fix to use (the new type encompassing the composite id or the self-reference) as the self-reference seems a little to hacky for my tastes.
If anyone finds out WHY this didn't work originally I'd still like to know...