Fluent NHibernate - override type for one specific property on one specific class? - fluent-nhibernate

I have a class that has a password property that I want to store encrypted in the db. The property is a string type, and I have a custom type EncryptedStringType that I want NHibernate to use to map this to the database. Here is my relevant automapping code:
var mappings = AutoMap.AssemblyOf<Business>()
.Where(x=>x.IsSubclassOf(typeof(EntityBase)))
.IgnoreBase(typeof(EntityBase))
.Conventions.Add
(
ConventionBuilder.Id.Always(x =>
x.GeneratedBy.HiLo(HILO_TABLE, HILO_COLUMN, HILO_MAX_LO)),
ConventionBuilder.HasMany.Always(x => x.Cascade.AllDeleteOrphan()),
Table.Is(o => Inflector.Pluralize(o.EntityType.Name)),
PrimaryKey.Name.Is(o => "Id"),
ForeignKey.EndsWith("Id"),
DefaultLazy.Always(),
DefaultCascade.All()
);
I cannot figure out the syntax to override the type for the UserPassword property of the Business class though. I thought I should be able to do something with overrides like:
mappings.Override<Business>(map=> /* Not sure what to do here */);
Any help is appreciated.

Found the answer myself.
mappings.Override<Business>(map =>
{
map.Map(x => x.UserPassword).CustomType<EncryptedStringType>();
});

You could always create a mapping override class. Any conventions that can still be applied will be, but you can basically specify mappings similarly to a ClassMap that override the default conventions.
Using the call to mappings.Override(), it'd look something like:
mappings.Override<Business>(map=>map.Map(x=>x.UserPassword).CustomType(typeof(EncryptedStringType)));

Related

meta program fluent validation

I have used fluent validation for hard code validations like this:
RuleFor(customer => customer.CreditLimit).GreaterThan(customer => customer.MinimumCreditLimit);
I guess it would not be a problem to replace MinimumCreditLimit by some (meta) database driven value in the code. Did someone ever attempt this and what would be the best practises in this context (apart from the fact that MinimumCreditLimit could stem from some strategy design pattern). Could one potentially use expression trees against fluent validation to make it even more meta program-ish?
Well, the easiest way would be to add a ctor to your Validation class.
public class EntityValidator : AbstractValidator<Entity> {
public EntityValidator(int minimumCreditLimit) {
Rulefor(customer => customer.CreditLimit).GreaterThan(minimumCreditLimit);
}
}
now you could use it like that (if you don't use the "attributes" way).
var minimumCreditLimit = <GetTheLimitFromDbWithAnyMethod>();
var validator = new EntityValidator(minimumCreditLimit);
<yourEntityInstance>.ValidateAndThrow(validator);
Another (similar) way would be to pass some way to get data from db to your validator (in ctor for example), and create a custom validator / extension method to use this.

NHibernate fluent Prevent children being updated

The application I have uses localization. The way it is built, is that it examines an entity (traversing down the structure) and translates every property marked as 'translate'.
The translations are stored in separate translation tables.
This is all fine but it leaves me with the problem that I now get the translated values in my 'default' values when I update the entity using the translations. And I don't want that.
Let me try and explain better.
Database:
The mapping of footprintlinevLue:
public class FootprintLineValueMap : ClassMap<FootprintLineValue> {
public FootprintLineValueMap() {
Table("FootprintLineValue");
Id(x => x.Id).GeneratedBy.Identity().Column("Id");
References(x => x.FootprintLine).Column("FootprintLineId");
References(x => x.CategoryValue).Column("CategoryValueId").Cascade.None();
}
As you can see a footprintline has multiple values that reference a categoryValue. The categoryvalue is localized.
When I now retrieve footprintlines our framework will put it through our translationservice and will automatically translate the Name and Description of the CategoryValue in the corresponding culture. If it cant find a translation in CategoryValueLocal, it will use the default in CategoryValue.
However...if I save a Footprintline, it will save the translated values back into CategoryValue (overwriting the default) instead of ignore it.
CategoryValues are not value objects and could be changed so I cant make them readonly.
I tried to map the reference as Cascade.None, but that doesn't seem to do anything.
I hope there is a way to simply mark this in the mapping so we can keep on using our TranslationService instead of having to figure out another way to hande localization.
mark the properties as not updateable.
Map(x => x.Description).Not.Update();
you could even define a convention to do so
class TranslatedPropertiesConvention : AttributePropertyConvention<Translated>
{
public void Apply(FluentNHibernate.Conventions.Instances.IPropertyInstance instance)
{
instance.Not.Update();
}
}

Fluent NHibernate does not call my ClassMap<ControlEntity> class

I use NHibernate for a dynamic website that its modules can be loaded dynamically, so when I want to build a sessionFactory, I use a way to find all assemblies and sort them with their dependencies
after all, I add them to Configuration instance I created and it works.
Now I want to change configuration type from hbm.xml files to fluent
I added below codes:
sessionFactory =
Fluently
.Configure()
.Database(
FluentNHibernate.Cfg.Db.MsSqlConfiguration.MsSql2008.ConnectionString(
c => c.FromAppSetting("connectionString")
)
)
.Mappings(
m => m.AutoMappings.Add(
AutoMap.Assemblies(
new FarayanConfig(),
assembliesArray
)
)
).BuildSessionFactory();
FarayanConfig is:
class FarayanConfig : DefaultAutomappingConfiguration
{
public override bool ShouldMap(Type type)
{
return type.Name.EndsWith("Entity");
}
public override bool IsVersion(FluentNHibernate.Member member)
{
return member.Name == "Version";
}
}
also I have a class in an assembly that will be loaded by this code (notice that assembly is not referenced, will be loaded dynamically) with a class named ControlEntity and also another class:
public class ControlEntityMap : ClassMap<ControlEntity>
{
public ControlEntityMap()
{
HasMany(x => x.Properties).Component(c => {
c.Map(v => v.Culture);
c.Map(v => v.Name);
c.Map(v => v.Value);
});
}
}
now the problem is constructor of ControlEntityMap will not execute!
what I must do?
Because of you are trying to use AutoMap.
You can use something like this:
.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.Load("your assembly name")))
Update:
You are doing right by ovverride DefaultAutomappingConfiguration for this situation but also you are trying to AutoMap all classes which ones end with "Entity" and your class which one you want to ignore it from AutoMap also ends with "Entity". I think you can seperate your classes in different namespaces and declare it in your ShouldMap property.
And there are some information in FluentNhibenate Wiki:
You can ignore base types by simply excluding them from your
ShouldMap(Type) method, that's sometimes the cleanest option; however,
if you want to be a bit more explicit you can use the IgnoreBase
method.
After AutoMap.AssemblyOf() we need to alter the conventions
that the auto mapper is using so it can identify our base-class.
AutoMap.AssemblyOf(cfg) .IgnoreBase();
We've added the IgnoreBase call which simply instructs the
automapper to ignore the Entity class; you can chain this call as many
times as needed.

Using WithConstructorArgument and creating bound type

I have a binding that looks like this:
kernel.Bind<IRepository<Holiday>>().To<RepositoryBase<Holiday>>();
The problem is that RepositoryBase takes a contructor paramter of UnitOfWork called context. This is not, in and of itself a problem. Ninject should resolve it. Except for the fact that I have two UnitOfWork implementations, both bound using an attribute discriminator.
kernel.Bind<IUnitOfWork>().To<MS_DevEntities>().WhenTargetHas<MsDataAttribute>()
.InRequestScope();
How can specify that when an IRepository is created, it should be created with MS_DevEntities?
Certainly, i could do something like this:
kernel.Bind<IRepository<Holiday>>().To<RepositoryBase<Holiday>>()
.WithConstructorArgument("context", new MS_DevEntities());
However, I would prefer to have Ninject create the instance, particularly because i'm using the .InRequestScope() lifecycle.
Any suggestions?
EDIT:
Previously, I was using a class that looked like this:
public class HolidayRepository : RepositoryBase<Holiday>, IHolidayRepository
{
public HolidayRepository([MsData]IUnitOfWork context) : base(context){}
}
However, I now find myself with several dozen of these and they don't do much but add extra work when I need to create a new repository. I'd like to just map these directly in the bindings.
EDIT2:
I suppose I could do something like this, but it seems kind of hackish. Is there a better way?
kernel.Bind<MS_DevEntities>().ToSelf().InRequestScope();
kernel.Bind<IRepository<Holiday>>().To<RepositoryBase<Holiday>>()
.WithConstructorArgument("context",
(context) => context.Kernel.Get<MS_DevEntities>());
E.g. Put the attribute to the entity and use something like this:
kernel.Bind(typeof(IRepository<>)).To(typeof(RepositoryBase<>));
kernel.Bind<IUnitOfWork>().To<MS_DevEntities>()
.When(r => EntityHas<MsData>(r));
kernel.Bind<IUnitOfWork>().To<TheOtherOne_DevEntities>()
.When(r => EntityHas<TheOtherData>(r));
bool EntityHas<TAttribute>(IRequest r)
{
return r.Target.Member.ReflectedType.IsGenericType &&
r.Target.Member.ReflectedType.GetGenericArguments()[0]
.GetCustomAttributes(typeof(TAttribute), false).Any();
}
You can do everything using this When condition and take the entity type from r.Target.Member.ReflectedType.GetGenericArguments()[0] to lookup somewhere which UoW that you have to use for this entity type.
2nd approch using config
kernel.Bind<IUnitOfWork>().To<TheOtherOne_DevEntities>()
.When(r => EntityNeedsUoW(r, 1));
bool EntityNeedsUoW(IRequest r, int id)
{
return UoWConfig.GetDbIdForEntity(
r.Target.Member.ReflectedType.GetGenericArguments()[0]) == id;
}

Fluent NHibernate - Setting CutomType IIdConvention

I have the following IIdConvention for a FluentNHibernate automapping. I want all of my id properties to use a custom type that is represented by a string property but the CustomType is never applied to my mappings.
public class PrimaryKeyHasTableName : FluentNHibernate.Conventions.IIdConvention
{
public void Apply(FluentNHibernate.Conventions.Instances.IIdentityInstance instance)
{
instance.Column(instance.EntityType.Name + "Id");
instance.CustomType<CustomIdType>();
}
}
When I looked into the FluentNHibernate source it appears that the Type for the id property has already been set so it is not being set by my convention.
If I use a ClassMap to map the class manually I have not problem setting the CustomType for the Identity property.
Id(x => x.Id)
.Column("UserId")
.CustomType<OnFileIdType>();
Does anybody know how I can successfully set the custom id property using a convention?
Or get my convention to run earlier in the mapping process so that the Type isn't already set by the time my code runs.
Also, here's my configuration code:
Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString(connString))
.Mappings(m =>
{
m.FluentMappings.AddFromAssemblyOf<BaseEntity>();
m.AutoMappings.Add(AutoMap.AssemblyOf<BaseEntity>()
.Where(t => t.Namespace.EndsWith("Models.Domain"))
.Conventions.AddFromAssemblyOf<BaseEntity>()
.UseOverridesFromAssemblyOf<BaseEntity>()
);
})
.ExposeConfiguration(CreateSchema)
.BuildSessionFactory();
Thanks.
I don't think you can achieve what you want with conventions.
One thing you can try is having all your entities subclass from an abstract entity that defines the Id property and has the custom type mapping for it.
I wouldn't recommend this however, It will just open room for more automapping problems.
Just go for the manual CustomType for each class map.
I'm having the exact same problem, it would be great if FNH's IIdConvention supported this.
After trying a few things and reading this I have resigned myself to implementing IAutoMappingOverride for entities using a custom type for their Id.
public class ProductMap : IAutoMappingOverride<Product>
{
public void Override(AutoMapping<Product> mapping)
{
mapping.Id(x => x.Id).CustomType<ProductId>();
}
}
Using automapping override instead of ClassMap will continue to automap the rest of your properties. Alter your AutoMappings initialisation code to include
.Overrides.AddFromAssemblyOf<BaseEntity>()
I am getting the same problem. I believe that it is arising from the invocation of Conventions.AddFromAssemblyOf<BaseEntity>(), which is causing your custom convention to not be applied.
(By the way, the posted code will work only if your convention classes are in the same assembly as your BaseEntity - it might be safer to use Conventions.AddFromAssemblyOf<PrimaryKeyHasTableName>())
A bug was raised about AddFromAssemblyOf back in February 2011: Fluent NHibernate - Setting CutomType IIdConvention. There is no resolution posted.
The work-around appears to be to add each of the Conventions explicitly
Conventions.Add<PrimaryKeyHasTableName>()
To check this, you can add the following line after the line which adds the automappings, in order to export the mappings to an hbm.xml file on your hard drive, and take a look at the generated mappings.
m.AutoMappings.ExportTo(#"C:\ExportedMappings")
Also, I suggest you add a breakpoint into the Apply method and run the code to ensure that it is being invoked.)