I'm having some problems with getting the following convention to work:
public class ColumnNameUpperConvention : IPropertyConvention
{
public void Apply(IPropertyInstance instance)
{
string cName = instance.Property.Name.ToUpper();
instance.Column(cName);
}
}
What I'm wanting the above code to do is to map a property called "Modified" to a column named "MODIFIED".
And this is my config:
var config =
Fluently.Configure()
.Database(OracleClientConfiguration.Oracle10
.ConnectionString(c => c.FromConnectionStringWithKey(cstringName)))
.Mappings(m =>
{
m.FluentMappings.AddFromAssemblyOf<AgilityObject>();
m.AutoMappings.Add(
AutoMap.AssemblyOf<AgilityObject>(mappingConfiguration)
.Conventions.Add<ColumnNameUpperConvention>());
})
.ExposeConfiguration(x => x.SetProperty("current_session_context_class", "thread_static"))
.ExposeConfiguration(x => x.SetProperty("generate_statistics", "true"))
.BuildSessionFactory();
When I debug I can see that my convention code gets executed, but it doesn't seem like it actually does anything.
Am I missing something?
PS. Do the mappings I've set explicitly in a ClassMap automatically override conventions? There are exceptions to the above convention and I want to map those properties by hand.
My bad. I needed to use IAutoMappingOverride instead of ClassMap if I am to use AutoMapping at all.
Related
I'm glad to set common cache for almost all the entity like the following with Fluent NHibernate:
public static FluentConfiguration Create(string connStr)
{
return Fluently.Configure()
.Cache(x => x.UseSecondLevelCache().ProviderClass<SysCacheProvider>())
.Mappings(m =>
{
m.FluentMappings
.AddFromAssemblyOf<UserMap>()
.Conventions.Add(
// here the cache is set ReadWrite
Cache.Is(x => x.ReadWrite()),
);
})
}
But there is still some entities that I DO NOT want to cache them. How should I do?
public class ActivityMap : EntityMap<Activity>
{
public ActivityMap()
{
References<User>(m => m.Executor);
//Note: I'm not want to change the cache but REMOVE the cache!
//Cache.ReadOnly();
}
}
I'm not sure it's a real solution or just a walk around that is to set the expiration=0 in the cache region node in web.config, but whatever it works.
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>()
I'm trying to set an unique constraint on the column LoginName of table User. So the following is my code:
public FluentConfiguration GetNHConfig()
{
var cfg = new FreeflyingConfiguration();
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString(_connStr))
.Mappings(m => m.AutoMappings
.Add(AutoMap.AssemblyOf<LogOfArticle>(cfg))
.Add(AutoMap.AssemblyOf<LogOfUser>(cfg))
// here is the problem, I think
.Add(AutoMap.AssemblyOf<User>(cfg).UseOverridesFromAssemblyOf<UserMappingOverride>())
.Add(AutoMap.AssemblyOf<Role>(cfg))
.Add(AutoMap.AssemblyOf<Profile>(cfg))
.Add(AutoMap.AssemblyOf<Blog>(cfg))
.Add(AutoMap.AssemblyOf<Comment>(cfg)));
}
public class UserMappingOverride : IAutoMappingOverride<User>
{
public void Override(AutoMapping<User> mapping)
{
// breakpoint is set here and can be hit every time
mapping.Map(x => x.LoginName).Not.Nullable();
mapping.Map(x => x.Email).Unique();
mapping.Map(x => x.Profile.BlogUrl).Unique();
}
}
The tables can be generated, and the breakpiont on line "" can be hit every time. But there is no change in database, which means, generate the Unique constraint, whatever I use UpdateSchema() or BuildSchema().
BTW, no error when executing.
So it's harder to find the reason. But any suggestion is welcome!
Are User, Role, Profile etc really in different assemblies? If they aren't you only need one .Add(AutoMap.AssemblyOf<T>(). This could be your problem because it might be overwriting your overrides on subsequent calls. I'm not all that familiar with overrides but it's worth a shot.
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString(_connStr))
.Mappings(m => m.AutoMappings
.Add(AutoMap.AssemblyOf<User>(cfg)
.UseOverridesFromAssemblyOf<UserMappingOverride>());
I have a application using NHibernate Auto Mapping... All working fine so far...
My Fluent Global.asax config:
private void InitializeNHibernateSession()
{
NHibernateSession.Init(
webSessionStorage,
new string[] { Server.MapPath("~/bin/Proj.Data.dll") },
new AutoPersistenceModelGenerator().Generate(),
Server.MapPath("~/NHibernate.config"));
}
But I need to map a class with Fluent mapping... I created the class :
namespace Proj.Data.NHibernateMaps
{
public class CategoryMap : IAutoMappingOverride<Category>
{
public void Override(AutoMapping<Category> mapping)
{
mapping.Id(x => x.Id)
.GeneratedBy.Identity();
mapping.Map(x => x.Description);
mapping.Map(x => x.UrlName);
mapping.References(x => x.ParentCategory)
.Not.LazyLoad();
}
}
}
The problem is that this mapping is never used by the NHibernate... Instead it uses the Auto Mapping generated Category...
How can I use my Fluent Mapping ?
Thanks
Paul
Wherever you're configuring the AutoPersistenceModel you need to reference the mapping overrides. I find the easiest way to do this is to just point it at the assembly containing the mapping overrides and let it discover all of them. That way you can add new IAutoMappingOverride implementations and it will be automatically picked up. You do this using the UseOverridesFromAssemblyOf extension method.
public class AutoPersistenceModelGenerator {
public AutoPersistenceModel Generate() {
return AutoMap.AssemblyOf<Category>()
.UseOverridesFromAssemblyOf<CategoryMap>();
}
}
Is it possible to use a Fluent NHibernate convention to map all ICollections as sets? I have an entity like so:
public class NoahsArk
{
public virtual ICollection<Animal> Animals { get; set; }
public NoahsArk()
{
Animals = new HashSet<Animal>();
}
}
With fluent mappings, this property would be mapped as HasMany(x => x.Animals).AsSet(), but how would I do this with a convention that I want to use with the automapper?
I should add that by default, ICollections get persisted as ILists, and I get a cast exception when it tries to cast the HashSet to IList.
This isn't possible in a convention, currently. If you want the automapper to treat your collections as sets by default, use ISet instead of ICollection.
In response to Christina's question, you have to create a new class that implements IAutoMappingOverride<T>:
public class AlbumOverride : IAutoMappingOverride<Album>
{
public void Override(AutoMapping<Album> mapping)
{
mapping.HasMany(x => x.Pictures).AsSet().Inverse();
}
}
Then tell FNH to use it in the configuration:
Fluently.Configure()
.Database(...)
.Mappings(m => m.AutoMappings.Add(AutoMap.Assemblies(...)
.UseOverridesFromAssemblyOf<Album>()))
.BuildConfiguration();
You'll need a new override class for every entity you need an override for, but it's mostly a copy and paste affair.