Guys,

This email is a heads up, with an opportunity to provide feedback before I
commit these changes to trunk. I want to make it clear that I'm not bashing
the work of the developers before myself who wrote the original conventions
code. I mean no disrespect, it's just not my idea of where it should
proceed.

Our current implementation of conventions is pretty unmaintainable, it's
merely a large class with several lambda functions that get called at
various stages in the mapping generation. Our mapping generation code has
logic for the conventions strewn about, and the convention functions
themselves are pretty awkward for anything other than really basic things
(once logic starts coming in, then the inline lambdas break down). There's
also no graceful degredation for support, we either support a convention or
we don't, there's very little room for people to work around missing
features, which is putting a lot of strain on future development. Finally,
when you're overriding a lot of conventions, your convention code can
quickly become large and cumbersome - there's no SoC.

Those are my reasons for what I've been working on - a complete rewrite of
the conventions code.

So how has it changed? The Conventions class has gone, for starters; which
means the inline overriding of conventions is gone too. Instead what you
have is a series of interfaces of varying degrees of granularity; any
classes implementing any of the interfaces will be automagically hooked into
FNHs generation cycle. What this equates to is you'll have a
folder/namespace dedicated to convention overrides, each class in there
making an alteration to the conventions when it's called. Because the
conventions are defined as interfaces, that means you can have a single
class handle multiple conventions of the same kind too.

An example or two:

public class TableNameConvention : IClassConvention
{
  public bool Accept(IClassMap classMap)
  {
    return classMap.EntityType.IsSubclassOf(typeof(Customer));
  }

  public void Apply(IClassMap classMap)
  {
    classMap.WithTable("Customer_" + classMap.EntityType.Name);
  }
}

public class ColumnNameConvention : IPropertyConvention, IIdConvention
{
  public bool Accept(IProperty property)
  {
    return true;
  }

  public bool Accept(IIdentityPart id)
  {
    return true;
  }

  public void Apply(IProperty property)
  {
    var column = GetColumnName(property.Property);

    property.ColumnName(column);
  }

  public void Apply(IIdentityPart id)
  {
    var column = GetColumnName(id.Property);

    id.ColumnName(column);
  }

  private string GetColumnName(PropertyInfo prop)
  {
    return prop.Name.ToLower();
  }
}

I'm very aware that these conventions are more verbose than our existing
ones, but the power and SoC is uncomparable.

The setup has now been reduced to:

WithConventions(conventions =>
  conventions
    .Add<TableNameConvention>()
    .Add<ColumnNameConvention>());

or simply:

WithConventions(conventions =>
  conventions.AddFromAssemblyOf<ColumnNameConvention>());

Which could actually be changed to implicitly find any conventions in the
same assembly as your mappings, but that's another discussion.

The interfaces you're provided with currently are:

   - IAssemblyConvention - Applied to an IEnumerable of IClassMap from each
   assembly
   - IClassConvention - Applied to each IClassMap
   - IMappingPartConvention - Applied to every mapping part in a IClassMap
   - IPropertyConvention - Applied to Map/Property's
   - IIdConvention - Ids
   - IVersionConvention - Versions
   - IComponentConvention & IDynamicComponentConvention - Components
   - IRelationshipConvention - Applied to all relationships
   - IHasManyConvention, IHasManyToManyConvention, IHasOneConvention,
IReferenceConvention
   - Applied to each relationship
   - IUserTypeConvention & UserTypeConvention base - For use with IUserTypes
   - IJoinConvention - Applied to joined tables
   - AttributePropertyConvention - Applied to properties with attributes

As you can see, there are a fair few options available. If we add a new
feature but forget to provide an interface for a convention, there's always
the level above instead. If IPropertyConvention didn't exist for example,
you could easily just implement IMappingPartConvention and write the Accept
method to only accept properties.

I suppose I'm asking if anyone has any major objections to these changes?
Are you ok with losing the simplicity of overriding one or two conventions
inline, for the net gain of more power?

James

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Fluent NHibernate" group.
To post to this group, send email to fluent-nhibernate@googlegroups.com
To unsubscribe from this group, send email to 
fluent-nhibernate+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/fluent-nhibernate?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to