EF4 Code First Control Unicode and Decimal Precision, Scale with Attributes

There are several attributes available when using code first with the Entity Framework 4 CTP5 Code First option.  When working with strings you can use [MaxLength(length)] to control the length and [Required] will work on all properties.  But there are a few things missing. By default all string will be created using unicode so you will get nvarchar instead of varchar.  You can change this using the fluent API or you can create an attribute to make the change.  If you have a lot of properties, the attribute will be much easier and require less code.

You will need to add two classes to your project to create the attribute itself:

1: public class UnicodeAttribute : Attribute

2: {

3: bool _isUnicode;

4: 

5: public UnicodeAttribute(bool isUnicode)

6: {

7: _isUnicode = isUnicode;

8: }

9: 

10: public bool IsUnicode { get { return _isUnicode; } }

11: }

12: 

13: public class UnicodeAttributeConvention : AttributeConfigurationConvention<PropertyInfo, StringPropertyConfiguration, UnicodeAttribute>

14: {

15: public override void Apply(PropertyInfo memberInfo, StringPropertyConfiguration configuration, UnicodeAttribute attribute)

16: {

17: configuration.IsUnicode = attribute.IsUnicode;

18: }

19: }

The UnicodeAttribue class gives you a [Unicode] attribute that you can use on your properties and the UnicodeAttributeConvention will tell EF how to handle the attribute.

You will need to add a line to the OnModelCreating method inside your context for EF to recognize the attribute:

1: protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)

2: {

3: modelBuilder.Conventions.Add(new UnicodeAttributeConvention());

4: base.OnModelCreating(modelBuilder);

5: }

Once you have this done, you can use the attribute in your classes to make sure that you get database types of varchar instead of nvarchar:

1: [Unicode(false)]

2: public string Name { get; set; }

Another option that is missing is the ability to set the precision and scale on a decimal.  By default decimals get created as (18,0).  If you need decimals to be something like (9,2) then you can once again use the fluent API or create a custom attribute.  As with the unicode attribute, you will need to add two classes to your project:

1: public class DecimalPrecisionAttribute : Attribute

2: {

3: int _precision;

4: private int _scale;

5: 

6: public DecimalPrecisionAttribute(int precision, int scale)

7: {

8: _precision = precision;

9: _scale = scale;

10: }

11: 

12: public int Precision { get { return _precision; } }

13: public int Scale { get { return _scale; } }

14: }

15: 

16: public class DecimalPrecisionAttributeConvention : AttributeConfigurationConvention<PropertyInfo, DecimalPropertyConfiguration, DecimalPrecisionAttribute>

17: {

18: public override void Apply(PropertyInfo memberInfo, DecimalPropertyConfiguration configuration, DecimalPrecisionAttribute attribute)

19: {

20: configuration.Precision = Convert.ToByte(attribute.Precision);

21: configuration.Scale = Convert.ToByte(attribute.Scale);

22: 

23: }

24: }

Add your line to the OnModelCreating:

1: protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)

2: {

3: modelBuilder.Conventions.Add(new UnicodeAttributeConvention());

4: modelBuilder.Conventions.Add(new DecimalPrecisionAttributeConvention());

5: base.OnModelCreating(modelBuilder);

6: }

Now you can use the following on your properties:

1: [DecimalPrecision(9,2)]

2: public decimal Cost { get; set; }

Both these options use the same concepts so if there are other attributes that you want to use, you can create them quite simply.  The key to it all is the PropertyConfiguration classes.   If there is a class for the datatype, then you should be able to write an attribute to set almost everything you need.  You could also create a single attribute to encapsulate all of the possible string combinations instead of having multiple attributes on each property.

All in all, I am loving code first and having attributes to control database generation instead of using the fluent API is huge and saves me a great deal of time.

This article is part of the GWB Archives. Original Author: Dane Morgridge

New on Geeks with Blogs

  • We Won The One Award I Actually Care About

    Full Scale made the Inc. 5000 for the fifth year straight, the 12th listing across my three companies. Here is why the one award you cannot buy is worth stopping for.

  • Your Customers Build the Features Now

    I let a tool I liked sit dead for a year rather than build the features I wanted. An MCP server meant I never had to, and your customers can do the same to your product.

  • Get the Size of a Directory in Linux the Easy Way

    du -sh for the quick answer, ncdu for the cleanup, df for the disk itself: every command for checking directory size in Linux, plus why du and df never agree.

  • Vim Search and Replace: The Ultimate Guide

    One :%s command replaces every match in a file before a find dialog would even open. The Vim substitute patterns worth the muscle memory: flags, ranges, capture groups, and multi-file edits.