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>());
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 am trying to follow this post using Fluent NHIbernate: http://blogs.planetcloud.co.uk/mygreatdiscovery/post/Localizing-entities-with-NHibernate.aspx
My test generates the following error:
----> NHibernate.MappingException : An association from the table TranslatedText refers to an unmapped class: .Domain.Localisation.ILocalizedEntity
Any idea how to get NH to honour the interface?
Adding .IncludeBase<ILocalizedEntity>() to my auto model did nothing... (as expected its an interface not an abstract right?)
Mappings: (Question)
mapping.HasMany(m => m.TranslatedTexts)
.AsSet()
.Inverse().Cascade.SaveUpdate()
.KeyColumn("EntityId")
.ForeignKeyConstraintName("none")
.Where("EntityClass = 'Domain.Question'");
TranslatedText (has) public virtual ILocalizedEntity Entity { get; set; }
mapping.ReferencesAny(tt => tt.Entity)
.IdentityType<Guid>()
.EntityIdentifierColumn("EntityId")
.EntityTypeColumn("EntityType");
Interface:
public interface ILocalizedEntity
{
ICollection<TranslatedText> TranslatedTexts { get; set; }
}
I've seen the same in the FNH test suite. I have a feeling it is something to do with the fact I use AutoMapping, but not sure what as yet...
edit
confirmed - using standard ClassMaps instead of automapping, with the same mappings above, works as expected.
I did find a "workaround" which was to remove the classes involved from automapping, and hand-roll them using ClassMaps, really not ideal since I HEART automapping!
sessionFactory = Fluently.Configure()
.Database(sqlConfig)
.Mappings(m => m.AutoMappings.Add(new MyAutoPersistenceModel().GetModel()))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<QuestionMap>())
.BuildSessionFactory();
In MyAutoPersistenceModel:
public override bool ShouldMap(System.Type type)
{
var interfaces = type.GetInterfaces();
return type != typeof(TranslatedText) &&
!interfaces.Any(x => x.GetType() == typeof(ILocalisedEntity)) &&
interfaces.Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEntityWithTypedId<>));
}
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've got an application talking to two databases, and it runs fine, and my tests pass, except when it tries to export the current DB schema, it outputs everything for both DBs in one block, and when it tries to validate the object model / DB schema line up, it tries to look in one database for everything, when one class (which is external data, hence the foreign DB) should not be mapped. I provided a mapping override for the class so that NH can correctly load/use data from the foreign DB (it's read-only), but now when I export my schema, it tries to make that table.
I tried IgnoreBase(typeof(Unit)) but this has no effect (whereas IgnoreBase(typeof(Entity)) does work correctly). I have decorated the custom repository methods with [SessionFactory(DataGlobals.FOREIGN_DB_FACTORY_KEY)] where that simply defines a constant string to use as a key for the SessionFactory, but I'm sure if there's something I need to decorate the class (Unit) with or pass a different parameter to SchemaExport ...
public void CanGenerateDatabaseSchema(){
var session = NHibernateSession.GetDefaultSessionFactory().OpenSession();
using (TextWriter stringWriter = new StreamWriter("../../../../db/schema/UnitTestGeneratedSchema.sql"))
{
new SchemaExport(configuration).Execute(true, false, false, session.Connection, stringWriter);
}
}
public void CanConfirmDatabaseMatchesMappings()
{
var allClassMetadata = NHibernateSession.GetDefaultSessionFactory().GetAllClassMetadata();
foreach (var entry in allClassMetadata)
{
NHibernateSession.Current.CreateCriteria(entry.Value.GetMappedClass(EntityMode.Poco))
.SetMaxResults(0).List();
}
}
In Fluent NHibernate you can use SchemaAction.None to disable the generation of the schema for a particular table.
Example:
public class BankInfoMap : ClassMap<BankInfo>
{
public BankInfoMap()
{
Schema(“viplookups.dbo”);
Table(“bnkroute”);
SchemaAction.None();
Id(x => x.Id).Column(“bnkrouteid”);
Map(x => x.AbaNumber).Column(“crouting”);
Map(x => x.Name).Column(“ccompname”);
Map(x => x.City).Column(“ccity”);
Map(x => x.State).Column(“cstate”);
Map(x => x.PhoneNumber).Column(“cphone1″);
}
}
Taken from: http://lostechies.com/rodpaddock/2010/06/29/using-fluent-nhibernate-with-legacy-databases/
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.