I have a proxy for a lazy entity which has been created in the session by loading a child entity. A subsequent fetch on the parent entity only returns the NH proxy. I need the actual instance to check the type (the entity has joined subclasses). I must be missing something, but I can't find a way to do this. Session.Refresh(proxy) does not appear to help, nor does any flavour of HQL that I've tried.
Can anyone help?
In my opinion, rather then solving this problem, you should rather rethink your design. Are you absolutely sure, that you can't use polymorphism in this situation - either directly make entity responsible for operation you're trying to perform or use visitor pattern. I came across this issue few times and always decided to change design - it resulted in clearer code. I suggest you do the same, unless you're absolutely sure that relying on type is the best solution.
In order to have example with at least some resemblance to the real world, let's suppose you have following entities:
public abstract class Operation
{
public virtual DateTime PerformedOn { get; set; }
public virtual double Ammount { get; set; }
}
public class OutgoingTransfer : Operation
{
public virtual string TargetAccount { get; set; }
}
public class AtmWithdrawal : Operation
{
public virtual string AtmAddress { get; set; }
}
It'd naturally be a small part of much larger model. And now you're facing a problem: for each concrete type of Operation, there's a different way to display it:
private static void PrintOperation(Operation operation)
{
Console.WriteLine("{0} - {1}", operation.PerformedOn,
operation.Ammount);
}
private static void PrintOperation(OutgoingTransfer operation)
{
Console.WriteLine("{0}: {1}, target account: {2}",
operation.PerformedOn, operation.Ammount,
operation.TargetAccount);
}
private static void PrintOperation(AtmWithdrawal operation)
{
Console.WriteLine("{0}: {1}, atm's address: {2}",
operation.PerformedOn, operation.Ammount,
operation.AtmAddress);
}
Simple, overloaded methods will work in simple case:
var transfer = new OutgoingTransfer
{
Ammount = -1000,
PerformedOn = DateTime.Now.Date,
TargetAccount = "123123123"
};
var withdrawal = new AtmWithdrawal
{
Ammount = -1000,
PerformedOn = DateTime.Now.Date,
AtmAddress = "Some address"
};
// works as intended
PrintOperation(transfer);
PrintOperation(withdrawal);
Unfortunately, overloaded methods are bound at compile time, so as soon as you introduce an array/list/whatever of operations, only a generic (Operation operation) overload will be called.
Operation[] operations = { transfer, withdrawal };
foreach (var operation in operations)
{
PrintOperation(operation);
}
There are two solutions to this problem, and both have downsides. You can introduce an abstract/virtual method in Operation to print information to selected stream. But this will mix UI concerns into your model, so that's not acceptable for you (I'll show you how can you improve this solution to meet your expectations in a moment).
You can also create lots of ifs in form of:
if(operation is (ConcreteType))
PrintOperation((ConcreteType)operation);
This solution is ugly and error prone. Every time you add/change/remove type of operation, you have to go through every place you used these hack and modify it. And if you miss one place, you'll probably only be able to catch that runtime - no strict compile-time checks for some of errors (like missing one subtype).
Furthermore, this solution will fail as soon as you introduce any kind of proxy.
The code below is VERY simple proxy (in this implementation it's same as decorator pattern - but those patterns are not the same in general. It'd take some additional code to distinguish those two patterns).
public class OperationProxy : Operation
{
private readonly Operation m_innerOperation;
public OperationProxy(Operation innerOperation)
{
if (innerOperation == null)
throw new ArgumentNullException("innerOperation");
m_innerOperation = innerOperation;
}
public override double Ammount
{
get { return m_innerOperation.Ammount; }
set { m_innerOperation.Ammount = value; }
}
public override DateTime PerformedOn
{
get { return m_innerOperation.PerformedOn; }
set { m_innerOperation.PerformedOn = value; }
}
}
As you can see - there is only one proxy class for whole hierarchy. Why? Because you should write your code in a way that doesn't depend on concrete type - only on provided abstraction. This proxy could defer entity loading in time - maybe you won't use it at all? Maybe you'll use just 2 out of 1000 entities? Why load them all then?
So NHibernate uses proxy like on above (much more sophisticated, though) to defer entity loading. It could create 1 proxy per sub-type, but it would destroy whole purpose of lazy loading. If you look carefuly at how NHibernate stores subclasses you'll see, that in order to determine what type entity is, you have to load it. So it is impossible to have concrete proxies - you can only have the most abstract, OperationProxy.
Altough the solution with ifs it's ugly - it was a solution. Now, when you introduced proxies to your problem - it's no longer working. So that just leaves us with polymorphic method, which is unacceptable because of mixing UI responsibility to your model. Let's fix that.
First, let's have a look at how the solution with virtual methods would look like (just added code):
public abstract class Operation
{
public abstract void PrintInformation();
}
public class OutgoingTransfer : Operation
{
public override void PrintInformation()
{
Console.WriteLine("{0}: {1}, target account: {2}",
PerformedOn, Ammount, TargetAccount);
}
}
public class AtmWithdrawal : Operation
{
public override void PrintInformation()
{
Console.WriteLine("{0}: {1}, atm's address: {2}",
PerformedOn, Ammount, AtmAddress);
}
}
public class OperationProxy : Operation
{
public override void PrintInformation()
{
m_innerOperation.PrintInformation();
}
}
And now, when you call:
Operation[] operations = { transfer, withdrawal, proxy };
foreach (var operation in operations)
{
operation.PrintInformation();
}
all works as a charm.
In order to remove this UI dependency in model, let's create an interface:
public interface IOperationVisitor
{
void Visit(AtmWithdrawal operation);
void Visit(OutgoingTransfer operation);
}
Let's modify model to depend on this interface:
And now create an implementation - ConsoleOutputOperationVisitor (I have deleted PrintInformation methods):
public abstract class Operation
{
public abstract void Accept(IOperationVisitor visitor);
}
public class OutgoingTransfer : Operation
{
public override void Accept(IOperationVisitor visitor)
{
visitor.Visit(this);
}
}
public class AtmWithdrawal : Operation
{
public override void Accept(IOperationVisitor visitor)
{
visitor.Visit(this);
}
}
public class OperationProxy : Operation
{
public override void Accept(IOperationVisitor visitor)
{
m_innerOperation.Accept(visitor);
}
}
What happens here? When you call Accept on operation and pass a visitor, implementation of accept will be called, where appropriate overload of Visit method will be invoked (compiler can determine type of "this"). So you combine "power" of virtual methods and overloads to get appropriate method called. As you can see - now UI reference here, model only depends on an interface, which can be included in model layer.
So now, to get this working, an implementation of the interface:
public class ConsoleOutputOperationVisitor : IOperationVisitor
{
#region IOperationVisitor Members
public void Visit(AtmWithdrawal operation)
{
Console.WriteLine("{0}: {1}, atm's address: {2}",
operation.PerformedOn, operation.Ammount,
operation.AtmAddress);
}
public void Visit(OutgoingTransfer operation)
{
Console.WriteLine("{0}: {1}, target account: {2}",
operation.PerformedOn, operation.Ammount,
operation.TargetAccount);
}
#endregion
}
And code:
Operation[] operations = { transfer, withdrawal, proxy };
foreach (var operation in operations)
{
operation.Accept(visitor);
}
I'm well aware that this isn't a perfect solution. You'll still have to modify the interface and visitors as you add new types. But you get compile time checking and will never miss anything. One thing that would be really hard to achieve using this method is to get pluggable subtypes - but I'm not convinced this is a valid scenario anyway. You'll also have to modify this pattern to meet your needs in concrete scenario, but I'll leave this to you.
To force a proxy to be fetched from the database, you can use the NHibernateUtil.Initialize(proxy)
method, or access a method/property of the proxy.
var foo = session.Get<Foo>(id);
NHibernateUtil.Initialize(foo.Bar);
To check if an object is initialized or not, you can use the NHibernateUtil.IsInitialized(proxy)
method.
Update:
To remove an object from the session cache, use the Session.Evict(obj)
method.
session.Evict(myEntity);
Info about Evict
and other methods for managing the session cache can be found in chapter 14.5 of the NHibernate docs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With