Sunday, 1 May 2011

Fluent NHibernate - Ignore Abstract Properties

I was struggling the other day whilst trying to have any property that started with the word "Display" be ignored by Fluent NHiberantes Automap feature. I had it working, but as soon as I added a abstract property to the base class, it all stopped working. I was using the older way of ignoring properties:
using System.Reflection;
using FluentNHibernate;
using FluentNHibernate.Automapping;
using FluentNHibernate.Cfg;

namespace FNHProblem
{
class Program
{
static void Main(string[] args)
{
Fluently .Configure()
.Database(FluentNHibernate.Cfg.Db.MsSqlConfiguration .MsSql2008.ConnectionString("Server=(local);Integrated Security=SSPI;" ))
.Mappings(mappings => mappings.AutoMappings.Add(AutoMap .Assemblies(Assembly .GetAssembly(typeof (Program )))
.OverrideAll(p => p.IgnoreProperties(ShouldIgnoreMember)))
.ExportTo("." ))
.BuildConfiguration()
.BuildSessionFactory();
}

public static bool ShouldIgnoreMember(Member member)
{
return member.Name.StartsWith("Display");
}
}

public abstract class BaseEntity
{
public virtual int Id { get; set; }

public abstract string DisplayString { get; }
}

public class EntityA : BaseEntity
{
#region Overrides of BaseEntity

public override string DisplayString
{
get { return "I am EntityA"; }
}

#endregion

public virtual string DisplaySomethingElse { get; set; }
}
}

But then switching to using a newer API fixes my problem straight away, so here is the solution:
using  System.Reflection;
using FluentNHibernate;
using FluentNHibernate.Automapping;
using FluentNHibernate.Cfg;

namespace FNHProblem
{
class Program
{
static void Main(string [] args)
{
Fluently .Configure()
.Database(FluentNHibernate.Cfg.Db.MsSqlConfiguration .MsSql2008.ConnectionString("Server=(local);Integrated Security=SSPI;" ))
.Mappings(mappings => mappings.AutoMappings.Add(AutoMap .Assembly(Assembly .GetAssembly(typeof (Program )), new CustomDefaultAutoMappingConfiguration ()))
.ExportTo("." ))
.BuildConfiguration()
.BuildSessionFactory();
}
}

class CustomDefaultAutoMappingConfiguration : DefaultAutomappingConfiguration
{
public override bool ShouldMap(Member member)
{
if (member.Name.StartsWith("Display" ))
{
return false ;
}
return base .ShouldMap(member);
}
}

public abstract class BaseEntity
{
public virtual int Id { get ; set ; }

public abstract string DisplayIShouldBeIgnored { get ; }
}

public class EntityA : BaseEntity
{
public override string DisplayIShouldBeIgnored
{
get { return "I am EntityA" ; }
}
}
}

Submit this story to DotNetKicks Shout it

Tuesday, 8 March 2011

ASP.NET MVC Getting a default route to point to an Area

This seems like such an obvious thing to want to do, but isn't clear from searching the web how this is done.
After many attempts, if found the solution, which is very easy:
 
routes.MapRoute("Defaults_Route" ,
"" ,
new { area = "MyArea" , controller = "Home" , action = "Index" }
).DataTokens.Add("area" , "MyArea" );

Submit this story to DotNetKicks Shout it

Tuesday, 9 June 2009

Accessing Properties without reflection and magic strings

Whilst some great refactoring tools will take care of magic strings for you, the use of them still grates on me whenever I am forced into using them and whilst using reflection can be very powerful it can also have a performance hit when used frequently.

Now, what do I mean by accessing properties?

What if you need to tell some object to use a property and its value, but it may need to access this property several times and the value might change. The last is the crux of the problem here.

If you pass the property in using standard property accessors, you will get the value as it stands at that time. If the property is mutable then this maybe ok, but what if it's not or the mutable object is replaced?

Well, you could pass the object and a magic string and use reflection to access the property when the new objects needs access, but there is always a penalty to using this approach.

However, using Lambdas and the power of closures, you now have an alternative to this approach:

Take a look at the following code:


using System;
using System.Diagnostics;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var vio = new SomeVeryImportantObject { VeryImportantProperty = "Top Secret" };
var moreImportantObject = new NeedInfoToWork();

moreImportantObject.SetAnothersPropertyToUseLaterUsingDelegates(() => vio.VeryImportantProperty);
moreImportantObject.SetAnothersPropertyToUseLaterUsingReflection(vio, "VeryImportantProperty");


vio.VeryImportantProperty = "Ok, not so important";

Console.WriteLine(moreImportantObject.GetValueNowUsingReflection());
Console.WriteLine(moreImportantObject.GetValueUsingClousers());

const int timesToAccess = 1000000;

var sw = Stopwatch.StartNew();

for (int i = 0; i < timesToAccess; i++)
{
var value = moreImportantObject.GetValueNowUsingReflection();
}

sw.Stop();
Console.WriteLine("Time Taken using reflection {0}ms", sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();

for (int i = 0; i < timesToAccess; i++)
{
var value = moreImportantObject.GetValueUsingClousers();
}

sw.Stop();
Console.WriteLine("Time Taken using closures {0}ms", sw.ElapsedMilliseconds);

Console.ReadKey();
}
}

public class SomeVeryImportantObject
{
public string VeryImportantProperty { get; set; }
}

public class NeedInfoToWork
{
private Func _propertyAccess;
private object _objectToAccess;
private string _propertyName;

public void SetAnothersPropertyToUseLaterUsingDelegates(Func propertyAccess)
{
_propertyAccess = propertyAccess;
}

public void SetAnothersPropertyToUseLaterUsingReflection(Object objectToGetPropertyValueFrom, string propertyName)
{
_objectToAccess = objectToGetPropertyValueFrom;
_propertyName = propertyName;
}

public string GetValueNowUsingReflection()
{
return _objectToAccess.GetType()
.GetProperty(_propertyName)
.GetValue(_objectToAccess, null)
.ToString();
}

public string GetValueUsingClousers()
{
return _propertyAccess();
}
}
}


This produced the following results on my computer:

> Ok, not so important
> Ok, not so important
> Time Taken using reflection 2076ms
> Take Taken using closures 56ms

Enough said.

We have improved performance and removed the use of magic strings.

Submit this story to DotNetKicks Shout it

Code Generation - yield and Lambdas

So, while I don't profess to be an expert on Code Generation, I do hope that some of the tips that I put up here may save someone else the time it took me to figure out how to accomplish what appear to be simple steps.

At the time of writing this post, and having spent several hours scouring the internet, I couldn't for the life of me find a way to get a yield return statement.

The reason for this will be explained in another post (TODO:addlink) but the basic premise was to have the following line in the generated class:

   01 yield return () => SomeStringProperty;

All the properties returned strings, so this was fine.

Trying to generate this was proving a problem, until I came across this...hmm...workaround (don't want to use the word hack here)
While it ties the generated code to be specifically C#, this, again was not a problem for the code base that we were working against.

Here is the code that produced the line:

  01 generatedProperty.GetStatements.Add(new CodeSnippetExpression(string.Format("yield return () => {0}", existingProperty.Name)));

The genereatedProperty is of type CodeMemberProperty as is the existingProperty.

I wouldn't recommend this for all solutions, but it worked in this case where we were not trying to add to a generic code generator.

Submit this story to DotNetKicks Shout it

Wednesday, 3 June 2009

Code Generation - Attributes with Enum Values

Adding attributes to a class seemed straight forward when writting a class to do some code generation, adding Enum values to the attribute didn't.

Here is the code for adding an attribute with a string value:

    1 type.CustomAttributes.Add(
    2     new CodeAttributeDeclaration(new CodeTypeReference(typeof (RangeAttribute)),
    3                                  new CodeAttributeArgument("Min",
    4                                                            new CodePrimitiveExpression("1"))));

Knowing how to add the Enum wasn't at first obvious until (after some googling and experimentation) I figured out that an enum value is really a field...obvious...

...ok, not so, but here is the result:

    1 var enumTypeExpression = new CodeTypeReferenceExpression(typeof(Format));
    2 var enumValueExpression = new CodeFieldReferenceExpression(enumTypeExpression, Format.Bool.ToString());
    3 
    4 type.CustomAttributes.Add(
    5     new CodeAttributeDeclaration(
    6         new CodeTypeReference(typeof (FormatAttribute)),
    7         new CodeAttributeArgument("Format", enumValueExpression)));

Submit this story to DotNetKicks Shout it