Conventions are not being honored

Andy's Avatar

Andy

21 May, 2010 02:12 PM via web

When using Fluent 1.0.0.363, I had the following Convention applied, which worked fine. Upgrading to anything newer and I get this exception:
FluentNHibernate.Cfg.FluentConfigurationException : An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.

----> NHibernate.MappingException : Could not compile the mapping document: (XmlDocument) ----> NHibernate.MappingException : Could not determine type for: MyNS.Price, MyNS for columns: NHibernate.Mapping.Column(PricePerUnit)

I can't stay on .363 through, because the ComponentMap and SubClassMap don't play nice together on that version. Fluent is finding all of my conventions as debugging I see it calling Accept for OTHER properties, but it doesn't ever call it for the Price struct. I have this same problem where i have a UserTypeConvention as well. It works fine in 363, but doesn't get applied in later versions.

Any ideas? Here's the convention:

public sealed class PriceConvention : IPropertyConvention, IPropertyConventionAcceptance {

#region IConventionAcceptance<IPropertyInspector> Members

public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
{
  criteria.Expect(x => x.Property.PropertyType == typeof(Price));
}

#endregion

#region IConvention<IPropertyInspector,IPropertyInstance> Members

public void Apply(IPropertyInstance instance)
{
  instance.CustomType<decimal>();
  instance.CustomSqlType("money");
}

#endregion

}

  1. Support Staff 2 Posted by James Gregory on 21 May, 2010 02:18 PM

    James Gregory's Avatar

    Nothing immediately obvious; although I don't understand how CustomType<decimal> would ever work, NHibernate wouldn't be able to translate a decimal to Price without an IUserType.

    Could you attach a project that recreates this issue?

  2. 3 Posted by Andy on 21 May, 2010 02:47 PM

    Andy's Avatar

    Yes, I just finished a project.

    It was working with Fluent .363, I thought through the PriceConvention I had setup.

    Andy

  3. 4 Posted by Andy on 21 May, 2010 02:55 PM

    Andy's Avatar

    Sorry, the connection string include in the Program.cs is wrong; it should be:
    Data Source=:memory:;Version=3;New=True;Pooling=True;Max Pool Size=1;

  4. 5 Posted by Andy on 21 May, 2010 03:07 PM

    Andy's Avatar

    Ok,

    I've fixed some unrelated issues in the sample. If you run the one I've attached here you'll encounter the error. Go into the lib folder and rename NFluentHibernate.dll ot something else, and rename the older version to take out the version number. Clean and rerun the solution, and everything works fine.

    Thanks
    Andy

  5. 6 Posted by Andy on 01 Jun, 2010 12:52 PM

    Andy's Avatar

    Has there been any update on this?

    Thanks
    Andy

  6. 7 Posted by Andy on 18 Jun, 2010 01:59 PM

    Andy's Avatar

    Hi,

    Was just wondering if the sample has been checked out yet? We could be doing something wrong too, but I'd like to get this resolved as we're stuck on .363 with some patches to make things work.

  7. Support Staff 8 Posted by Paul Batum on 27 Jun, 2010 07:00 AM

    Paul Batum's Avatar

    Hi Andy,

    I've taken a look at your sample and I think I can explain why its not
    working.

    The short of it is that currently, an IPropertyConvention will not be
    applied to any properties that exist within a component that was mapped
    using a ComponentMap. The reason for this is that if the code applied
    conventions to components defined using component maps, there's a good
    chance those conventions would be applied more than once because the
    component mapping is shared between all the different places it is used.
    Applying these conventions more than once is usually harmless but there are
    some cases, such as when figuring out the appropriate column names for
    component members, where it causes problems.

    I've implemented a workaround for this that resolves the issue, but its a
    bit of a hack so really I want James to look at it as this ComponentMap
    stuff is his baby and he knows it much better than I do. I've sent him a
    mail so we'll see what he says. In the mean time, you can try my version of
    FNH with the fix here:
    http://github.com/paulbatum/fluent-nhibernate/tree/dev

    Let me know how it goes.

  8. 9 Posted by Andy on 28 Jun, 2010 02:39 PM

    Andy's Avatar

    Hi Paul,

    Thanks for taking the time to look into this. I understand what the issues may be, but I think it's important that this works. Otherwise isn't everyone stuck using types NHibernate natively knows?

    Unfortunately the fix didn't work for us; we get a PropertyNotFoundException, as it seems something else goes wrong. Consider this code (Sqlite is not required, as it never gets to the point of building the mappings).

    using FluentNHibernate.Cfg;
    using NUnit.Framework;
    using FluentNHibernate.Mapping;
    using FluentNHibernate.Cfg.Db;
    using NHibernate.Tool.hbm2ddl;
    
    namespace ComponentIssues
    {
      [TestFixture]
      public class ComponentPropertyNotFound
      {
        [Test]
        public void PropertyNotFound()
        {
          var config = Fluently.Configure()
            .Database(
              SQLiteConfiguration.Standard
                .ConnectionString("Data Source=:memory:;Version=3;New=True;Pooling=True;Max Pool Size=1;")
                .Raw("connection.release_mode", "on_close")
                .DefaultSchema("Shopping")
            ).Mappings(m =>
              m.FluentMappings.AddFromAssemblyOf<MyClassMap>()
            )
            .BuildConfiguration();
    
          using (var sessionFactory = config.BuildSessionFactory())
          {
            using (var session = sessionFactory.OpenSession())
            {
              new SchemaExport(config).Execute(false, true, false, session.Connection, null);
            }
          }
        }
      }
    
      public struct MyStruct
      {
        public decimal Value
        {
          get;
          private set;
        }
      }
    
      public class MyClass
      {
        public virtual int Id
        {
          get;
          private set;
        }
    
        public virtual MyStruct MyValue
        {
          get;
          set;
        }
      }
    
      public sealed class MyClassMap : ClassMap<MyClass>
      {
        public MyClassMap()
        {
          Id(x => x.Id).GeneratedBy.Native().UnsavedValue(0);
          Component(x => x.MyValue);
        }
      }
    
      public sealed class MyStructMap : ComponentMap<MyStruct>
      {
        public MyStructMap()
        {
          Map(x => x.Value);
        }
      }
    }
    

    If there's another way we can acomplish what we need to do I'm open to that. Maybe I'm not seeing another solution because I'm just learning Nhibernate & Fluent.

    Thanks
    Andy

  9. 10 Posted by cremor on 29 Jun, 2010 07:46 AM

    cremor's Avatar

    I think I'm having the same problem. I just updaded from paulbatum-fluent-nhibernate-1.0-testers-2-331-g8294f2a (compiled myself) to 1.1.0.686 (binary download from page) because I also would like to have conventions for ComponentMaps, but now I'm having the problem that the generated mapping XML is invalid.
    Instead of creating just the compontent XML node with its sub component and properties as child nodes, it creates many nested component nodes and properties.

    Example for correct mapping:

    <component name="OuterComponent">
      <component name="InnerComponent">
        <property name="InnerProp1"/>
        <property name="InnerProp2"/>
        <property name="InnerProp3"/>
      </component>
      <property name="OuterProp"/>
    </component>
    

    Example of the now produced invalid mapping:

    <component name="OuterComponent">
      <component name="InnerComponent">
        <component name="InnerComponent">
          <property name="InnerProp1"/>
          <property name="InnerProp2"/>
          <property name="InnerProp3"/>
        </component>
        <property name="InnerProp1"/>
        <property name="InnerProp2"/>
        <property name="InnerProp3"/>
      </component>
      <component name="OuterComponent">
        <component name="InnerComponent">
          <component name="InnerComponent">
            <property name="InnerProp1"/>
            <property name="InnerProp2"/>
            <property name="InnerProp3"/>
          </component>
          <property name="InnerProp1"/>
          <property name="InnerProp2"/>
          <property name="InnerProp3"/>
        </component>
        <property name="OuterProp"/>
      </component>
      <property name="OuterProp"/>
    </component>
    
  10. Support Staff 11 Posted by Paul Batum on 30 Jun, 2010 11:25 AM

    Paul Batum's Avatar

    Okay, yes, there's definitely an issue with my attempted fix, thanks for
    letting me know. I'm working on a resolution.

  11. Support Staff 12 Posted by Paul Batum on 30 Jun, 2010 12:09 PM

    Paul Batum's Avatar

    I've asked James to revert the offending commit. Andy, I'm going to have to
    look at your problem a bit more carefully as it looks like my quick fix was
    a bad idea.

    Sorry for the trouble.

    Paul.

  12. 13 Posted by Andy on 30 Jun, 2010 12:16 PM

    Andy's Avatar

    Paul,

    No problem, I appreciate you looking into this. Checking out the change was no problem, I just reverted back to our hacked version of fluent.

Reply to this discussion

Preview Comments are parsed with Markdown. Help with syntax

Attached Files

    You can attach files up to 10MB

    What number comes after 20?