FluentNHibernate - Getting the entity name when mapping. Current method being made obsolete - nhibernate

I am currently automatically naming my tables in fluent NHibernate by using AutoMappingOverride's and setting the name of the table to the pluralised name of the entity like so.
public class PersonMappingOverride : IAutoMappingOverride<Person>
{
public void Override(AutoMapping<Person> mapping)
{
mapping.Table(mapping.EntityType.Name.Pluralize());
mapping.Id(x => x.PersonId).Column("PersonId").GeneratedBy.Increment();
mapping.Map(x => x.Name).CustomSqlType("nvarchar(200)");
}
}
public static string Pluralize(this string input)
{
return System.Data.Entity.Design.PluralizationServices.PluralizationService.CreateService(new CultureInfo("en-US")).Pluralize(input);
}
I am getting the following error.
'FluentNHibernate.Mapping.ClasslikeMapBase.EntityType' is obsolete: 'Do not call this method. Implementation detail mistakenly made public. Will be made private in next version.'
Does anyone know the correct way of getting the entity name? I've done a fair bit of Googling and have only found examples of people using this obsolete method to achieve what I need.
Cheers
Steve
Thanks for all the great help guys. Using conventions is way more elegant for my use case than the overrides anyway.
var sqlConfig = MsSqlConfiguration.MsSql2005.ConnectionString(ConnectionString);
var config = Fluently.Configure().Database(sqlConfig);
config.Mappings(c => c.AutoMappings.Add(AutoMap.AssemblyOf<User>(new IJAutomappingConfiguration()).Conventions.AddFromAssemblyOf<TableNamingConvention>()));
public class TableNamingConvention : IClassConvention
{
public void Apply(IClassInstance instance)
{
instance.Table(instance.EntityType.Name.Pluralize());
}
}
Here is the full code to get this working.

Here's how you would do it using a Convention:
public class NamingConvention : IClassConvention
{
public void Apply(IClassInstance instance)
{
instance.Table(instance.EntityType.Name.Pluralize());
}
}

Maybe trying Conventions, FluentNHibernate Conventions

Related

NInject IBindingGenerator and ToProvider

I've created this code:
public class AddonsModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
this.Bind(b => b.FromAssembliesMatching("*")
.SelectAllClasses()
.InheritedFrom(typeof(UIExtensibility.AbstractAddon))
.BindWith(new AddonBindingGenerator())
);
}
private class AddonBindingGenerator : IBindingGenerator
{
public System.Collections.Generic.IEnumerable<Ninject.Syntax.IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(System.Type type, Ninject.Syntax.IBindingRoot bindingRoot)
{
if (type.IsInterface || type.IsAbstract)
yield break;
yield return bindingRoot.Bind(type).ToProvider(typeof(UIExtensibility.AbstractAddon));
}
}
private class AddonProvider : IProvider<UIExtensibility.AbstractAddon>
{
public object Create(IContext context)
{
return null;
}
public Type Type
{
get { throw new NotImplementedException(); }
}
}
}
AddonProvider seems be avoided. This is never performed.
When I perform:
kernel.GetAll<UIExtensibility.AbstractAddon>(), AddonProvider.Create method is never performed.
Could you tell me what's wrong?
I'll appreciate a lot your help.
Thanks for all.
AddOnProvider is inheriting from IProvider<T> instead of UIExtensibility.AbstractAddon.
also, you may have issues binding to private inner classes. make AddOnProvider a public top level class.
You're binding a specific type which inherits from typeof(UIExtensibility.AbstractAddon) to a provider. For example, there could be a class Foo : UIExtensibility.AbstractAddon.
Now your convention binding translates to this:
Bind<Foo>().ToProvider<AddonProvider>();
Now, kernel.GetAll<UIExtensibility.AbstractAddon>() however is looking for bindings made like:
Bind<UIExtensibility.AbstractAddon>().To...
Fix It
So what you need to do is change the line
bindingRoot.Bind(type).ToProvider(new AddonProvider());
to:
bindingRoot.Bind(typeof(UIExtensibility.AbstractAddon)).ToProvider<AddonProvider>();
Furthermore
you're line object f = bindingRoot.Bind(type).ToProvider(new AddonProvider()); is never returning the binding (object f).
does UIExtensibility.AbstractAddon implement IProvider?
Thanks for your answer and comments.
I believe the trouble is on I'm not quite figuring out how this "generic" binding process works.
I'm going to try writing my brain steps process out:
I need to bind every AbstractAddon implementation inside addons assemblies folder. So, I think this code is right, but I'm not sure at all.
this.Bind(b => b.FromAssembliesMatching("*")
.SelectAllClasses()
.InheritedFrom(typeof(UIExtensibility.AbstractAddon))
.BindWith(new AddonBindingGenerator())
);
My AbstractAddon is like:
public abstract class AbstractAddon : IAddon
{
private object configuration;
public AbstractAddon(object configuration)
{
this.configuration = configuration;
}
// IAddon interface
public abstract string PluginId { get; }
public abstract string PluginVersion { get; }
public abstract string getCaption(string key);
public abstract Type getConfigurationPanelType();
public abstract System.Windows.Forms.UserControl createConfigurationPanel();
}
I guess I need to:
foreach implementation of `AbstractAddon` found out,
I need to "inject" a configuration object ->
So, I guess I need to set a provider and provide this configuration object.
This would be my main way of thinking in order to solve this problem.
I've changed a bit my first approach. Instead of using a IBindingGenerator class, I've used the next:
public class AddonsModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
this.Bind(b => b.FromAssembliesMatching("*")
.SelectAllClasses()
.InheritedFrom(typeof(UIExtensibility.AbstractAddon))
.BindAllBaseClasses()
.Configure(c => c.InSingletonScope())
);
this.Bind<object>().ToProvider<ConfigurationProvider>()
.WhenTargetHas<UIExtensibility.ConfigurationAttribute>();
}
So, My ConfigurationProvider is:
private class ConfigurationProvider : IProvider<object>
{
public object Create(IContext context)
{
return "configuration settings";
}
}
And now, my AbstractAddon constructor contains the parameter annotated with ConfigurationAttribute as:
public AbstractAddon([Configuration]object configuration)
{
this.configuration = configuration;
}
The problem now, NInject seems to ignore the configuration object provider. NInject generates a dump object, however, not perform ConfigurationProvider.Create method...
What I'm doing wrong, now?
Is this approach really better than the last one?
Thanks for all.

Fluent NHibernate table naming convention not working

I have the following convention which I load into my FNH config
public class TableNameConvention : IClassConvention, IClassConventionAcceptance
{
public void Accept(IAcceptanceCriteria<IClassInspector> criteria)
{
criteria.Expect(x => x.TableName, Is.Not.Set);
}
public void Apply(IClassInstance instance)
{
var tableName = instance.EntityType.Name.Pluralise();
instance.Table(tableName);
}
}
I do not specify table names on any of my mappings, yet this convention is not applied. I'm using Fluent NHibernate 1.4.1.1. Can anyone spot anything I might have done wrong?
UPDATE
The conventions are loaded in the following manner:
public static NHibernate.Cfg.Configuration BuildConfiguration()
{
var connectionStringName = "mydb";
return Fluently.Configure(new NHibernate.Cfg.Configuration())
.Database(MsSqlConfiguration
.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey(connectionStringName))
.Dialect<MsSql2008Dialect>()
.AdoNetBatchSize(50))
.Mappings(m =>
{
m.FluentMappings.AddFromAssemblyOf<Profile>();
m.FluentMappings.Conventions.Add(DefaultLazy.Always(), DynamicUpdate.AlwaysTrue(), DynamicInsert.AlwaysTrue());
m.FluentMappings.Conventions.AddFromAssemblyOf<HiLoConvention>();
})
.ExposeConfiguration(config => config.SetProperty(NHibernate.Cfg.Environment.CurrentSessionContextClass, typeof(ManagedWebSessionContext).AssemblyQualifiedName))
.ExposeConfiguration(HiLoConvention.CreateScript)
.ExposeConfiguration(RunSchemaUpdate)
.BuildConfiguration();
}
All conventions sit in the same assembly and namespace as the HiLoConvention referenced above in the .AddFromAssembly() method call.
UPDATE 2:
The problem is in the Accept() method, because if I remove this method (and also the IClassConventionAcceptance interface from the class declaration) then the convention is applied. I have also tried this expectation to no avail
criteria.Expect(x => string.IsNullOrEmpty(x.TableName))
The original code worked with Fluent 1.2.1...
This question is old, but perhaps this can help someone else:
I assume you wanted to set the convention on each entity, unless a table name was specified explicitly in the map. So to achieve that, you can simply do the following:
public class TableNameConvention : IClassConvention
{
public void Apply(IClassInstance instance)
{
var tableName = instance.EntityType.Name.Pluralise();
instance.Table(tableName);
}
}
This will apply the convention on all entities, unless TableName was specified explicitly in the map.
Have you tried
m.FluentMappings.ConventionDiscovery.AddFromAssemblyOf<HiLoConvention>()
in place of
m.FluentMappings.Conventions.AddFromAssemblyOf<HiLoConvention>()

Optional SubclassMap (left join) with NHibernate 3.0 GA & FNH

Disclaimer: I'm fairly new to NH & ORM in general.
Disclaimer: I'm working with a build of FNH from here in order to use with NH3.0GA.
The problem in a nutshell is that I would like to use FNH's SubclassMap as a way to map a LEFT JOIN, table-per-subclass scenario to my object hierarchy which is defined as:
public class MyBaseClass {
public virtual int Id { get; set; }
}
public class MySubClass : MyBaseClass {
public virtual string SubClassVal { get; set; }
}
This is mapped via FNH as:
public class MyBaseClassMap : ClassMap<MyBaseClass> {
public MyBaseClassMap() {
Table("BaseClass");
Id(x => x.Id, "Id").GeneratedBy.Assigned();
}
}
public class MySubClassMap : SubclassMap<MySubClass> {
public MySubClassMap() {
Table("SubClass");
KeyColumn("Id");
Map(x => x.SubClassVal);
}
}
And I retrieve via:
public class Repository {
ISession session; //assume properly initialized ISession
public IList<T> GetAll<T>() where T: class {
return session.CreateCriteria<T>().List<T>();
}
}
And in my database, I've got 1 record in my BaseClass table, 0 records in SubClass.
Now, what I would like to do is pull the entity out as a MySubClass instance by doing something like this:
var rep = new Repository();
var subclasses = rep.GetAll<MySubClass>();
And of course, there are no instances in the returned collection as this is presumably performing an INNER JOIN underneath it all. This is where I'm stuck. I've managed to discover that specifying an 'optional' join is what I'm supposed to do. I've attempted to modify MySubClassMap to:
public class MySubClassMap : SubclassMap<MySubClass> {
public MySubClassMap() {
Join("SubClass", j => {
j.KeyColumn("Id");
j.Optional();
j.Map(x => x.SubClassVal); // note that I've tried the map outside the Join() below, to no avail
});
//Map(x => x.SubClassVal);
}
}
Compiling/running this presents me with the following (innermost) exception:
The element 'joined-subclass' in namespace 'urn:nhibernate-mapping-2.2' has invalid child element 'join' in namespace 'urn:nhibernate-mapping-2.2'. List of possible elements expected: 'property, many-to-one, one-to-one, component, dynamic-component, properties, any, map, set, list, bag, idbag, array, primitive-array, joined-subclass, loader, sql-insert, sql-update, sql-delete, resultset, query, sql-query' in namespace 'urn:nhibernate-mapping-2.2'.
I'll save posting the stack trace, but the jist of it is:
MyApp -->
FluentNHibernate.Cfg.FluentConfiguration.BuildSessionFactory() -->
NHibernate.Cfg.FluentConfiguration.BuildConfiguration()
I think that's all the relevant info. I suspect I may be bumping into a breaking change between this very new version of NH and version of FNH that isn't so new. But, as mentioned earlier, I am a rookie, and could well be doing something stupid. If this is the case, I'd very much appreciate somebody smacking me over the head with what probably should be obvious.
Thanks in advance.
Entities have one type, which doesn't change. If you have a record in your BaseClass table only, that entity is and will always be a MyBaseClass.
If entities can change their "type", you shouldn't use inheritance but composition.

Fluent nhibernate automapping collection

I am trying to map my collections with FNHib automapping. The problems that I want to solve are:
1) I want all my collections in the project to be mapped via private field. How can I say that globally?
2) Is there any way to automap bidirectional relationship without explicitly overriding each of my entities.
class OrganizationEntity example:
private ISet<> _collectionWarehouse;
public virtual IEnumerable<WarehouseEntity> CollectionWarehouse
{
get{return _collectionWarehouse; }
set{_collectionWarehouse = new HashedSet<WarehouseEntity>((ICollection<WarehouseEntity>)value)}
}
Class WarehouseEntity example:
public virtual OrganizationEntity Organization{get;set;}
You can map your collections to a private field 'globally' with the following convention:
// assumes camel case underscore field (i.e., _mySet)
public class CollectionAccessConvention : ICollectionConvention
{
public void Apply(ICollectionInstance instance) {
instance.Access.CamelCaseField(CamelCasePrefix.Underscore);
}
}
Whenever you want to set a 'global' automap preference in FNH, think conventions. The you use the IAutoOverride on a given class map if you need to.
As far has the set (a HashSet is usually what I really want also) part, the last time I had to do some mapping, I did need to do an override, like:
public class ActivityBaseMap : IAutoMappingOverride<ActivityBase>
{
public void Override(AutoMapping<ActivityBase> m)
{
...
m.HasMany(x => x.Allocations).AsSet().Inverse();
}
}
I do agree that should translate into a convention though, and maybe you can do that these days. Please post if you figure it out.
HTH,
Berryl
CODE TO USE A HASHSET as an ICollection =================
public virtual ICollection<WarehouseEntity> Wharehouses
{
get { return _warehouses ?? (_warehouses = new HashSet<WarehouseEntity>()); }
set { _warehouses = value; }
}
private ICollection<WarehouseEntity> _warehouses;

Private collection mapping in fluent nhibernate

How can I map this:
public class Customer
{
private IList<Order> _orders;
public IEnumerable<Order>
GetAllOrders()
{
return _orders;
}
}
On the project page are some samples but none is about this situation.
There is this sample:
// model
public class Account
{
private IList<Customer> customers = new List<Customer>();
public IList<Customer> Customers
{
get { return customers; }
}
}
// mapping
HasMany(x => x.Customers)
.Access.AsCamelCaseField();
But it assumes that Account has public field Customers and that scenario is different as mine. I tried some possible options but none works:
HasMany(x => Reveal.Propertie("_orders"))
Private fields works fine in simple property mapping but collection mapping
is quite different. Any idea? Thanks
The easiest solution is to expose your collection as a public property Orders instead of the GetAllOrders() method. Then your mapping is
HasMany(x => x.Orders)
.Access.AsCamelCaseField(Prefix.Underscore);
and your class is
public class Customer
{
private IList<Order> _orders = new List<Order>();
public IEnumerable<Order> Orders
{
get { return _orders; }
}
}
If that doesn't work for you, it is possible to map private properties using Fluent NHibernate's Reveal mapping.
Edited to add: Having just done this, the correct answer is:
HasMany<Order>(Reveal.Property<Customer>("_orders")) etc.
The collection must be exposed as a protected virtual property to allow proxying:
protected virtual IList<Order> _orders { get; set; }
This answer put me on the right track.
Thanks.
Your solution is fine. However, there could be situations(hypotetical) when you dont want to reveal your private collection. This mapping scenario is not explained in your linked post because there is difference between mapping simple propertie as descibed in that post and collection mapping. My attempt to use HasMany(x => Reveal.Propertie("_orders")) failed because of raised exception.
You can map a completely private collection using Reveal.Member(), but it has a specific and non-obvious restriction: the Expression that HasMany() accepts has to return either IEnumerable<TReferenced> or object.
For your class:
public class Customer
{
private IList<Order> _orders;
public IEnumerable<Order> GetAllOrders()
{
return _orders;
}
}
the following line will populate the _orders collection:
HasMany(Reveal.Member<Customer, IEnumerable<Order>>("_orders"));
//additional mapping behaviors
For completeness - the following line gives a compiler error:
HasMany(Reveal.Member<Customer, IList<Order>>("_orders"));