1

I started a new project and for this project i wanted to use BasicSample (NHibernate best practise, http://www.codeproject.com/Articles/13390/NHibernate-Best-Practices-with-ASP-NET-1-2nd-Ed) i haven´t used this before and now i get problems. In this project i use NHibernate 3.3.1 and modified the source code from BasicSample to use my entieties. I get this error for every class model (just showing for the class "Month"):

System.TypeInitializationException was unhandled by user code

Message=The type initializer for 'Nested' threw an exception. Source=Project.Data TypeName=Nested StackTrace: at Project.Data.NHibernateSessionManager.get_Instance() in Project.Data\NHibernateSessionManager.cs:line 28 at Project.Web.NHibernateSessionModule.BeginTransaction(Object sender, EventArgs e) in App_Code\NHibernateSessionModule.cs:line 27 at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) InnerException: NHibernate.InvalidProxyTypeException Message=The following types may not be used as proxies: Project.Core.Domain.Calendar.Month: method Equals should be 'public/protected virtual' or 'protected internal virtual' Project.Core.Domain.Calendar.Month: method IsTransient should be 'public/protected virtual' or 'protected internal virtual' Project.Core.Domain.Calendar.Month: method get_Year should be 'public/protected virtual' or 'protected internal virtual' Project.Core.Domain.Calendar.Month: method set_Year should be 'public/protected virtual' or 'protected internal virtual' Blockquote

the class looks like:

public class Month : DomainObject<int>
{
    private Year _year;
    public Year Year
    {
        get { return _year; }
        set { _year = value; }
    }

    private string _monthName; 
    public string MonthName
    {
        get { return _monthName; }
        set { _monthName = value; }
    }

    private IList<Consumption> consumptions = new List<Consumption>();
    public IList<Consumption> Consumptions
    {
        get { return new List<Consumption>(consumptions).AsReadOnly(); }
        protected set { consumptions = value; }
    }

    public Month()
    { }

    public override int GetHashCode()
    {
        return (GetType().FullName + "|" +
                MonthName.GetHashCode()).GetHashCode();
    }

Does anoyone know what the problem could be? I have been crosschecking my project and the BasicSample project but i can´t find anything that missmatch.

2.Can someone explain for me how to use the GetHashCode from DaomainObject because i don´t know how to use this one in every class= Should every property in the class be added here?

I hope someone can help me.

Thommie
  • 67
  • 1
  • 11

2 Answers2

3

The problem is contained in your exception stack trace. You need to read them more carefully:

The following types may not be used as proxies:
Project.Core.Domain.Calendar.Month: method Equals should be 'public/protected virtual' or 'protected internal virtual'
Project.Core.Domain.Calendar.Month: method IsTransient should be 'public/protected virtual' or 'protected internal virtual'
Project.Core.Domain.Calendar.Month: method get_Year should be 'public/protected virtual' or 'protected internal virtual'
Project.Core.Domain.Calendar.Month: method set_Year should be 'public/protected virtual' or 'protected internal virtual'

What it says is basically, that you need to make all public and protected members of your class virtual, otherwise lazy loading won't work.


GetHashCode:
The hash code of an instance should not change over the course of its lifetime, therefore you shouldn't include properties that can be changed.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • I had all the members public virtual. Then i tried as the sample project.. they didn´t have virtual. I have changed back to virtual but i still get the same error. – Thommie Aug 17 '12 at 14:12
  • 1
    @Thommie: I am sure you are not getting the **same** error. You might post the new call stack. Or try reading it carefully yourself and check whether you can figure it out yourself. I assume `DomainObject.IsTransient` is still not `virtual`. – Daniel Hilgarth Aug 17 '12 at 14:14
  • i asure you its the same error. The following types may not be used as proxies: ( 'All the members is public virtual) Project.Core.Domain.Calendar.Month: method Equals should be 'public/protected virtual' or 'protected internal virtual' Project.Core.Domain.Calendar.Month: method IsTransient should be 'public/protected virtual' or 'protected internal virtual' Project.Core.Domain.Calendar.Month: method get_Id should be 'public/protected virtual' or 'protected internal virtual' Project.Core.Domain.Calendar.Month: method set_Id should be 'public/protected virtual' or 'protected internal virtual' – Thommie Aug 17 '12 at 14:18
  • 2
    @Thommie: You must be kidding me :-) Please compare the two error messages. They are **not** the same! – Daniel Hilgarth Aug 17 '12 at 14:19
  • Sorry Daniel it was aslmost the same! Found it. but don´t know how the equal method should be declared.. now it is public override sealed bool Equals(object obj) – Thommie Aug 17 '12 at 14:25
2
  1. NHibernate uses lazy loading by default. It performs it by creating proxy classes from your entities - inheriting from your entity and overriding it's members. In order for this to work, you need to mark all of your entity members as virtual. That was what it complains about in exception message.

  2. As for GetHashCode, you should implement it in DomainObject and only use Id in GetHashCode overrides. You should also override Equals. Here you can find reasons why: NHibernate: Reasons for overriding Equals and GetHashCode.

Community
  • 1
  • 1
Miroslav Popovic
  • 12,100
  • 2
  • 35
  • 47
  • I had all the members public virtual. Then i tried as the sample project.. they didn´t have virtual. I have changed back to virtual but i still get the same error – Thommie Aug 17 '12 at 14:14
  • Your DomainObject should have Id as virtual member. That's the problem. And also other members of DomainObject. – Miroslav Popovic Aug 17 '12 at 14:19
  • 1
    Also, while there, it should be enough to have GetHashCode/Equals overrides in DomainObject only. – Miroslav Popovic Aug 17 '12 at 14:20
  • how should this look like?public override sealed bool Equals(object obj) { DomainObject compareTo = obj as DomainObject; return (compareTo != null) && (HasSameNonDefaultIdAs(compareTo) || // Since the IDs aren't the same, either of them must be transient to // compare business value signatures (((IsTransient()) || compareTo.IsTransient()) && HasSameBusinessSignatureAs(compareTo))); } – Thommie Aug 17 '12 at 14:24
  • Yes, something like that... You check for nulls, then check if they are transient (not saved) and compare references in that case, and lastly check if their ids are equal. An example: http://blog.nerdbank.net/2006/01/why-equals-and-gethashcode-are-so.html – Miroslav Popovic Aug 17 '12 at 14:29
  • Also, you must not have `sealed` modifier on Equals method, but `virtual`, since the lazy-loading will fail again. – Miroslav Popovic Aug 17 '12 at 14:31