This question appears to be related to my previous question.
I have now finished implementing AutoMapper across my entire application and I am down to one map that in very specific circumstances does not work.
I have put together a unit test with some fake classes that is able to reproduce the problem every time, the unit test itself has some setup that configures ActiveRecord to run against an in memory database that I have not included here (let me know if it may be relevant).
Here is the unit test:
[Test]
public void SandBox()
{
Mapper.CreateMap<TestDbParty, TestCustomer>();
Mapper.CreateMap<TestDbParty, TestLazyCustomer>();
string customerId;
using (Transaction.CreateParticipant())
{
var dbCustomer = new TestDbParty();
dbCustomer.Save();
customerId = dbCustomer.Id;
}
using (var uow = Transaction.CreateParticipant())
{
var dbCustomer = TestDbParty.Find(customerId);
var customer = Mapper.Map<TestCustomer>(dbCustomer);
var lazyCustomer = Mapper.Map<TestLazyCustomer>(dbCustomer);
}
}
//Fake classes for unit test
public class TestCustomer
{}
public class TestLazyCustomer : TestCustomer
{}
[ActiveRecord("PARTY", Lazy = true)]
public class TestDbParty : DbActiveRecord<TestDbParty>
{
[PrimaryKey(PrimaryKeyType.Sequence, "ID", SequenceName = "PARTY_ID_SQ")]
public virtual string Id { get; set; }
}
Transaction.CreateParticipant is a wrapper to setup the SessionScope, here is the implementation:
return new ActiveRecordTransactionParticipant((TransactionScope)SessionScope.Current
?? new TransactionScope())
The last line of the test will throw the following exception:
System.InvalidCastException : Unable to cast object of type 'MyProject.TestCustomer'
to type 'MyProject.TestLazyCustomer'.
Now if the test is changed to only map to the LazyCustomer it works as expected or if the map calls are moved into the first transaction they both work, reordering the two lines so that the lazy customer is mapped first also works.
My guess here is that the Castle proxying is somehow causing this but I can't figure out how or how I can reliably fix this.
Edit: I put a break point on the failing line and ran dbCustomer.GetType()
in the immediate window, this returned Castle.Proxies.TestDbPartyProxy
so that appears to confirm my suspicion at least partially, the mapping would work fine when they are in the same transaction because the object is infact an instance of TestDbParty
and not a proxy.
This is definitely the problem, after removing the Lazy=true
on the TestDbParty
class the test works fine.