3

I am using NHibernate 3.1 and Fluent NHibernate as ORM in my project. I need to have a property of a POCO ignored by Fluent NHibernate. At first, my post might look as exact duplicate of this question, but it is not.

My complications come first from the fact that the POCOs are defined in a different assembly than the mapping and I am using fluent mappings for my POCOs. I have additional requirement not to write ingore-property code where the session factory configuration takes place (this happens at a centralized place outside the modules), but as part of the module that defines the mappings. Ideally, I believe the right place would be the concrete ClassMap implementation, since it knows exactly how to describe a POCO to the ORM.

However, I am stuck on this mainly because this is my first impact with NHibernate and its fluent API. Up to now I am having very good impression of its capabilities and extensibility, and I hope there is a way to achieve my requirement in a way that the mapping related code is encapsulated in its corresponding module.

Here is my configuration, from a centralized place:

List<Assembly> assemblies = GetModules().Select(x => x.GetType().Assembly).ToList();

ISessionFactory nhibernateSessionFactory = Fluently
    .Configure()
    .Mappings(m => assemblies.ForEach(asm => m.FluentMappings.AddFromAssembly(asm)))
    .Database(
        MsSqlConfiguration.MsSql2005
            .ShowSql()
            .ConnectionString(DatabaseConfig.Instance.ConnectionString))
    .ExposeConfiguration(c => new SchemaUpdate(c).Execute(true, true))
    .BuildSessionFactory();

I use standard class mappings that inherit from ClassMap:

public class User
{
    public virtual int ID { get; set; }
    public virtual String Username { get; set; }
    public virtual String Password { get; set; }
    public virtual DateTime DateCreated { get; set; }
    public virtual DateTime DateModified { get; set; }

    // Must ignore
    public string ComputedProperty  { get { ... } }
}

public class UserMap : ClassMap<User>
{
    public UserMap()
    {
        Table("User");
        Id(x => x.ID).GeneratedBy.Identity();
        Map(m => m.Username).Not.Nullable().Length(255).UniqueKey("User_Username_Unique_Key");
        Map(m => m.Password).Not.Nullable().Length(255);
        Map(m => m.DateCreated).Not.Nullable();
        Map(m => m.DateModified).Not.Nullable();
    }
}
Community
  • 1
  • 1
Ivaylo Slavov
  • 8,839
  • 12
  • 65
  • 108

3 Answers3

5

I know this post is bit old, but I post anyway since I didn't find any up todate posts on the subject. I guess the easiest way should be to add an attribute to each property we dont want to be persisted to a table. By add a extension that check if it has for eg. has a [NoEntity] attibute.

/// <summary>
/// Tells a single Property to not be persisted to table.
/// </summary>
public class NoEntity : Attribute { }


    /// <summary>
/// Extension to ignore attributes
/// </summary>
public static class FluentIgnore
{
    /// <summary>
    /// Ignore a single property.
    /// Property marked with this attributes will no be persisted to table.
    /// </summary>
    /// <param name="p">IPropertyIgnorer</param>
    /// <param name="propertyType">The type to ignore.</param>
    /// <returns>The property to ignore.</returns>
    public static IPropertyIgnorer SkipProperty(this IPropertyIgnorer p, Type propertyType)
    {
        return p.IgnoreProperties(x => x.MemberInfo.GetCustomAttributes(propertyType, false).Length > 0);
    }
}

And in the fluent config setup:

            return Fluently.Configure()
            .Database(DatabaseConfig)
            .Mappings(m => m.AutoMappings.Add(AutoMap.Assembly(typeof(IDependency).Assembly)
            .OverrideAll(p => {
                p.SkipProperty(typeof(NoEntity)); 
            }).Where(IsEntity)))
            .ExposeConfiguration(ValidateSchema)
            .ExposeConfiguration(BuildSchema)
            .BuildConfiguration();
Bootproject
  • 94
  • 1
  • 6
  • Interesting approach! If only I did not have to keep my entities clean from ORM-related annotations (I have the mappings in a separate assembly, so I can reuse my entity classes from other assemblies without bringing any orm dependencies). I'll try to achieve the above effect via my mapping classes. – Ivaylo Slavov Dec 19 '12 at 14:58
  • This will ignore any property that has any attributes on it at all. Probably not desired or expected behavior. – Justin Morgan - On strike Apr 02 '15 at 02:26
4

I think you are right that the ClassMap is the best place to ignore this property.

Example:

.Override<Shelf>(map =>  
{  
  map.IgnoreProperty(x => x.YourProperty);
});

Documentation: https://github.com/jagregory/fluent-nhibernate/wiki/Auto-mapping#ignoring-properties

As far as getting the mappings from another assembly, it should be as easy as something like this (depending on your current configuration):

.Mappings(m =>
              {
                  m.FluentMappings.AddFromAssemblyOf<ProvideClassFromYourOtherAssembly>();
              });
shanabus
  • 12,989
  • 6
  • 52
  • 78
  • OK, but that way I need to know each class that must have a property ignored in the centralized initialization place, and have it explicitly configured. That is what I am trying to avoid. Imagine if I have to refactor a module, I must also modify the application ORM initialization too. – Ivaylo Slavov Mar 15 '12 at 20:43
  • In your question, you say "I have additional requirement not to set ingoring the property in the session factory configuration (which happens at a centralized place) but as part of the module that defines the mappings." but now you are saying that this is the problem with my answer? Maybe I don't understand what you are asking, sorry. – shanabus Mar 15 '12 at 21:14
  • Sorry, I had a wrong impression that the overriding occurs at the centralized place where the session factory is being configured, my bad. The overrider interface can be put in the same assembly where I have defined my mapping. – Ivaylo Slavov Mar 15 '12 at 21:44
  • 2
    -1. What are you calling `.Override` and `.Mappings` on? Besides, link is dead. – joozek Apr 01 '14 at 14:33
  • 3
    I've updated the dead link. Does that really merit a -1 for an accepted answer? I'm not in control of other peoples websites, links die. As for the examples, check the updated documentation link for a better context of what they are on - https://github.com/jagregory/fluent-nhibernate/wiki/Auto-mapping#ignoring-properties – shanabus Apr 01 '14 at 20:03
  • Unfortunately, the documentation is not complete. Where should I put this override inside the `ClassMap`? – rabejens Jan 30 '18 at 08:25
  • @rabejens the Override would go on the AutoMap like so: `AutoMap.AssemblyOf().Override(...)` – shanabus Jan 31 '18 at 18:49
  • @shanabus could you please point out what does `ClassInYourAssembly` mean in this context? Thank you – ibanjo Mar 04 '20 at 13:43
  • @ibanjo you want to replace `ClassInYourAssembly` with the name of a class that is inside the same assembly where your classes are that you want automapped. So looking at the original Question, you might choose to use `User`. This allows the Assembly scanning to find other classes in the assembly and build auto mappings for them. – shanabus Mar 04 '20 at 15:09
0

Will not Justin. This is the thing with this extension. Just the property you want gets ignored.

public class Person : IEntity{ 
 public virtual string Name{..}
 public virtual string Lastname{..}

 [NoProperty]
 public virtual string FullName{ // Not created property
  get { return Name +  " " + Lastname;  }
 }
}

public class Group : IEntity{ 
 public virtual string FullName{..} //Created property
}
Bootproject
  • 94
  • 1
  • 6