Data Annotations in the Entity Framework and Code First


Data annotation attributes were introduced in .NET 3.5 as a way to add validation to classes used by ASP.NET applications. Since that time, RIA Services has begun using data annotations and they are now part of Silverlight.  Code First allows you to build an EDM Entity Framework model using code (C# or VB.NET) and is now in its third CTP.

Feedback we’ve received from these CTPs shows demand for Code First to read data annotation attributes from class and property definitions to configure aspects such as maximum string length, which properties are keys, or the table name in which to store a type of entity.

This post outlines which existing data annotation attributes we’ll adopt and which new attributes we are proposing.

Using Data Annotations

When building a model using Code First, you start by writing a set of entity classes. For example:

public class Book
{
    public string ISBN { get; set; }
    public string Title { get; set; }
    public string AuthorSSN { get; set; }
    public Person Author { get; set; }
}

public class Person
{
    public string SSN { get; set; }
    public string Name { get; set; }
    public ICollection<Book> Books { get; set; }
}

When using this class model with Code First in CTP3, you would need to use the fluent API to describe which properties are keys, which relationships exist, and the length of each string property if you wanted these to be constrained. These are very common tasks and we’d like users of Code First to be able to make these kinds of configuration without having to use the fluent API to describe the model. Using data annotation attributes, the above model characteristics can be made declaratively as part of the class definition:

public class Book
{
    [Key]
   
public string ISBN { get; set; }

    [StringLength(256)]
    public string Title { get; set; }

    public string AuthorSSN { get; set; }

    [RelatedTo(RelatedProperty=“Books”, Key=”AuthorSSN”, RelatedKey=”SSN”)]
    public Person Author { get; set; }
}

public class Person
{
    [Key]
    public string SSN { get; set; }

    [StringLength(512)]
    public string Name { get; set; }

    [RelatedTo(RelatedProperty=”Author”)]
    public ICollection<Book> Books { get; set; }
}

Existing Data Annotation Attributes

There are several existing data annotation attributes in the System.ComponentModel.DataAnnotations namespace that can be used by Code First. These are:

KeyAttribute

KeyAttribute is used to specify that a property/column is part of the primary key of the entity and applies to scalar properties only.

StringLengthAttribute

StringLengthAttribute is used to specify the maximum length of a string. As there is no minimum length in Code First or EF, the “MinimumLength” property on the attribute would be ignored. This attribute applies only to properties that are of type string.

In .NET 4.0, a negative MaximumValue is not allowed. but in the next version of the framework the recommendation is to change this behavior so that a value of ‘-1’ means “max”. This isn’t ideal, so another idea we are considering is to make a MaxStringLengthAttribute that derives from StringLengthAttribute. The MaxStringLengthAttribute wouldn’t take parameters, but would just assume the maximum allowable value.

ConcurrencyCheckAttribute

ConcurrencyCheckAttribute is used to specify that a property/column has a concurrency mode of “fixed” in the EDM model. A fixed concurrency mode means that this property is part of the concurrency check of the entity during save operations and applies to scalar properties only.

RequiredAttribute

RequiredAttribute is used to specify that a property/column is non-nullable and applies to scalar, complex, and navigation properties:

  • Scalar properties: means this property is non-nullable (even if the CLR type says it is nullable).
  • Complex properties: the attribute is not allowed here so we would throw an exception
  • Navigation properties
    • Collection property: the attribute is not allowed here so we would throw an exception
    • Reference property: this means the backing FK property is non-null, and that the end of the association is cardinality “1” (instead of 0..1).

TimestampAttribute

The TimestampAttribute is used to specify that a byte[] property/column has a concurrency mode of “fixed” in the model and that it should be treated as a timestamp column on the store model (non-nullable byte[] in the CLR type). This attribute applies to scalar properties of type byte[] only. and only one TimestampAttribute can be present on an entity as this is what is allowed on most database platforms.

DataMemberAttribute

The DataMemberAttribute, while not strictly part of the data annotation collection, can be used to help specify the ordinal of primary keys. This is important on entities where there is a composite primary key and you want to make an assertion about the order the keys are specified on the database or are used in your application. This attribute applies only to scalar properties only that are part of the key. Ordinals do not need to be consecutive, they only specify the relative order of the key properties in metadata.

Ideally we’d like to be able to specify the key order as part of the KeyAttribute via an “Ordinal” property, but we can’t make changes to KeyAttribute until the next release of the .NET framework.

New Data Annotation Attributes

While the existing data annotation attributes provide many useful options for defining your model, there are still several common cases where we’d like to be able to make model changes with annotation attributes. Our goal with data annotation support in Code First is not to provide another way to completely specify a model, but to provide a mechanism that addresses the most common kinds of configurations that developers need to influence their model.

This is an area where it would be great to get early feedback so we can incorporate your ideas into our data annotation plan – below are descriptions of the annotation attributes we are proposing for Code First.

RelatedToAttribute

The RelatedToAttribute is used for two things:

  • To assign bi-directionality to certain relationships where the built-in convention doesn’t detect it
  • To associate a navigation property with its foreign key(s)

The RelatedToAttribute is placed on navigation properties and can be present on zero, one, or both ends of a relationship. There are a few parameters on the RelatedToAttribute:

  • A property to optionally specify the RelatedProperty on the target type.
    This is to support bi directionality in relationships (Book.Author is related to Person.Books, for example).
  • A property to optionally specify the keys on this entity that constrain the relationship.
    This can be either the primary key(s) if the attribute is on a navigation property on the principal end of a relationship, or the foreign key(s) if the attribute is on a navigation property on the dependent end of a relationship.
  • A property to optionally specify the keys on the related entity that constrain the relationship.
    This can be either the primary key(s) if the attribute is on a navigation property on the dependent end of a relationship, or the foreign key(s) if the attribute is on a navigation property on the principal end of a relationship.
  • A property to optionally specify cascade delete behavior.
    When this property is set to true and the principal entity is deleted, the dependent end of the relationship will also be deleted.

In the example at the beginning of the blog post, the RelatedToAttribute was used to related the Book.Author and Person.Books navigation properties so that all of Book.AuthorSSN, Book.Author, and Person.Books represent the same relationship in the model.

We also considered using the existing AssociationAttribute to specify relationships. however this attribute assumes that there already is a backing model and requires a relationship name and required key properties which are not needed when describing your model with Code First.

LengthAttribute

LengthAttribute can be used to specify the maximum length of an array type, such as a byte[] and applies only to properties. A value of ‘-1’ means “max” and all other negative values are not allowed. There is overlap here with the StringLengthAttribute: when the LengthAttribute is specified on a property of type string, the semantics will be the same as StringLengthAttribute.

StoreGeneratedAttribute

The StoreGeneratedAttribute can be used to specify that a property’s value is generated on the database store and the only store generated pattern supported in the first version is “identity”. This attribute applies to properties only and has a single optional nullable boolean property Identity. A null value for Identity means that no decision should be made for Identity: the convention or an explicit API call will be made to turn the identity pattern on or off.

StoreNameAttribute

The StoreNameAttribute can be used to specify a name for a store/database item. This attribute has different meanings depending on the kind of thing this attribute applies to:

  • If the attribute is on a context class, it means “database name”.
  • If the attribute is on an entity class, it means “table name”.
  • If the attribute is on a property in an entity class, it means “column name”.

StoreIgnoreAttribute

StoreIgnoreAttribute can be used to specify that a CLR type or property should not be included when reading type or property metadata from a CLR type. This attribute can apply to classes, which means they should not be considered as an EntityType or ComplexType object but can also apply to properties, which means that property should not be part of the EntityType or ComplexType. We haven’t finalized the name of this attribute yet, so if you have suggestions, please let us know.

StoreInlineAttribute

StoreInlineAttribute can be used to specify that a CLR type should be considered as a ComplexType when reading type metadata from CLR types. Complex types can be thought of as a class without an identity/keys, or a logic grouping of properties (such as an Address or PhoneNumber) and applies only to class definitions. ComplexTypes are stored inline with the entity. We may choose not to include this attribute as the convention we are thinking of adding to Code First should detect most cases where a complex type is being used.

Other Possibilities

There may be other kinds of model definition that you’d like to be able to do using data annotation attributes. Some other candidates are:

  • Being able to specify whether a string is unicode or not
  • Being able to specify whether a type is variable or fixed length
  • Having data annotation attributes put CSDL annotations in your model that other systems (such as OData) can read. An example of this is the RangeAttribute.

Let us know if any of these options sound interesting or if there is something else you’d like us to consider.

Summary

Code First will offer a few different ways of configuring a model: purely by built-in conventions, using data annotation attributes to make certain kinds of model changes, or by using a fluent API to fully customize the model. To provide more flexibility over the existing data annotation attributes, we are adding new attributes that Code First can use.

We’d like to hear your feedback on the set of attributes that are available and how Code First will use them.

Jeff Derstadt
Entity Framework Team


Comments (50)

  1. Pablo Castilla says:

    Hi, nice work, but it could go further.

    I would like a full tag modeling, as JPA or nhibernate, where you declare all: the mapped table and so on.

    I would be nice to have the option of avoiding the edmx

    Nice work!.

  2. Higor Ramos says:

    Hello People, until now I’ve not thought about configure model using annotations. I think it is a great idea, You’re going so well with Fluent API but I’l like to use annotations too. Are you going do implement it or just thinking?

  3. Jeff says:

    @Higor

    It is our plan to implement this set of Data Annotations and incorporate any feedback we receive on naming or additional useful attributes. This should be available in the next CTP of Code First.

    Thanks,

    Jeff

  4. Jeff says:

    @Pablo

    We have thought about the idea of offering a full declarative syntax for describing the mapping. Right now we don’t have plans to do this for the first release, but we’ll take it into consideration for the future.

    You will be able to express full mapping with the fluent API.

    Jeff

  5. Ben Gichamba says:

    I would prefer a StoreTypeAttribute over a TimestampAttribute. This way, the store type can be specified. The reason is that you may need to specify other data types as well. An example that comes to mind is decimal. By default, generating an SQL Server db from code first will make all decimal fields decimal(18, 0). But you may want them saved as money.

    When the StoreGeneratedAttribute has value of Identity, it would be important to somehow specify whether this should apply to the EDM only or both the EDM and the data store. This is because it is possible to have more than one column with the StoreGeneratedPattern property set to Identity in the EDM. A good thing. However RDBMS, specifically SQL server will not allow you to have more than one Identity column in a table. So, trying to create database from model or Code-first with multiple fields’ StoreGeneratedPattern property set to Identity will not succeed and will raise the error: “Multiple identity columns specified for table ‘TableName’. Only one identity column per table is allowed.”

  6. Ben Gichamba says:

    IsUniqueAttribute?

  7. Tommy Fannon says:

    How about an attribute to mark something as transient?  

    Perhaps I am missing something, but I have been searching for the last hour on how to make one of my POCO classes’ attributes not created in the database when i do a context.CreateDatabase().

    Does anyone know how to specify this in fluent syntax?

  8. @Tommy says:

    In CodeFirst CTP3 there isn’t a way to "exclude" a property from an entity, but this is something we are adding to the fluent API and the set of annotations. The attribute called "StoreIgnoreAttribute" that is described above is the annotation. We considered calling this StoreTransientAttribute, but we aren’t sure if that is globally recognized since "Ignore" is more common in .NET.

    Jeff

  9. Jeff says:

    @Tommy

    In CodeFirst CTP3 there isn’t a way to "exclude" a property from an entity, but this is something we are adding to the fluent API and the set of annotations. The attribute called "StoreIgnoreAttribute" that is described above is the annotation. We considered calling this StoreTransientAttribute, but we aren’t sure if that is globally recognized since "Ignore" is more common in .NET.

    Jeff

  10. Jeff says:

    @Ben

    Uniqueness: right not the EF doesn’t support unique constraints, but this is something we are likely to add in the next release after VS 2010. At that time we’ll update the Code First API and annotations to support this constraint.

    Store type: We’ll support TimestampAttribute since it is already present as part of the existing data annotation attributes. As for adding a StoreTypeAttribute, we’ve considered this but found that there are only a limited number of cases where you would need this (such as specifying decimal scale and precision). There would be complicated interactions between attributes such as StringLengthAttribute and StoreTypeAttribute as to which should take precedence. However, it is still on the table and we appreciate your feedback.

    Jeff

  11. Karl says:

    I prefer anemic domain models because my entities may have different behavior depending on their usage context. So if I’d have to divvy up my $100 budget, I wouldn’t invest in EF data annotations for code first. At least, not for now. Instead, I’d put some more towards default mapping configuration – much like Fluent NHibernate’s auto-mapping.

    None the less, hats off to you and the guys working on EF code first – all your efforts are much needed and appreciated!

    Karl

  12. sipo says:

    there is not a way to drop one table or drop all table but not drop the database

  13. lynn eriksen says:

    When might we see a Code First beta?

  14. sipo says:

    StringLength Attribute should have a minimal property

    And IndexAttribute is important too

    Range Attribute should be seperate as MinAttribute MaxAtribute

    AllowNegative

    AllowDecimal etc.

  15. nnn says:

    [Exclude]

    [DbKey(IsDbGenerate=false), Length(50)]

    [DbTable("User")]

    StringColumn(IsUnicode=true

    [Index("Name_Age", ASC = false, UNIQUE = true)]

    [HasOne(OrderBy = "Id DESC")]

    [RelateTo, DbColumn("Person_Id")]

  16. Stefan says:

    I’d like to know if is there a way to modify the existing POCO template so taht in the generated entities I could have a some ‘validation’ attribues set such as [Key] or [StringLength] for (some of) the properties? – based on existing database schema… Is it feasible?

  17. Damien says:

    Could you put in a "Category" string property to the base ValidationAttribute so validation messages could be categorised, say into Errors, Warnings, Informational ?

  18. Andrej says:

    Hi Jeff,

    I consider the Data-Annotations with the full declarative mapping possibilities as a "must" to be usable in an enterprise architecture. Right now, the EDMX is a handy toy for very little one-shot apps. The "fluent API", avoiding the funny wizard/EDMX toys, is surely the right way for handling databases with n-1000 tables. But nobody wants to call the API to get the mappings, it's good enough for a few tables, but for a large db it's a pain. It definitely needs to be expressed declarative, much like L2S, NHibernate etc.. Right now, no serious architect considers EF as an valid option for larger databases, which is a pity.

    Thank you,

    Andrej

  19. T.Haug says:

    Hi,

    I have just discovered that post.

    I have already started a small project to do the same thing… argh, I thought I am the only one 😉

    My solution looks the following (it is heavily influenced by JPA and (N)HIbernate) because I am using these in customer projects).

    I am currently only able to map simple types because of too less time to implement more.

    But perhaps this could also give you some ideas:

    [Entity (Name="DB_TableName)]

    public class IntegrationTestEntity {

      [Id]

      [Column(Name = "TEST_ID")]

      public long Id { get; set; }

      [Column(Length=20, Nullable=false)]

      public string Name { get; set; }

      [Column(Name = "TEST_VORNAME", Nullable=true)]

      public string Firstname { get; set; }

      [Transient]

     public int donotStoreInDB { get; set;}

    }

    Most of the Annotations are optional like the Column Attribute because I would like to have convention over configuratio. So if I don't specify any thing my framework uses common sense defaults (e.g. if name in Column Attribute is missing the property name is used as column name).

    Kind reagrds,

    Thomas

  20. I noticed in Scott Gu's blog post that the table columns were alphabetical instead of the same order in the class.

    Can you please not sort the properties by name and then insert the columns into the table?

    At a minimum, offer an option to sort or not sort.

    Thanks!

    Karl

  21. David Fauber says:

    Is there any way currently to specify the database name that should be used for a given DbContext?  (like what the proposed DataStoreName when used on a DbContext will do?)

  22. frennky says:

    consider a MVVM pattern, in some scenarios model is not sufficient so you need a viewmodel wich usually has a few members that are model classes or some members of model classes. in such a case, you would have way too many classes that are very similar, often two times more than if you could use mvc pattern.

    now, if you could specify that certan property is a column in one table and another property that is a column in other table than you could map tables (models) directly into your viewmodels.

  23. Matthew Wills says:

    Is the RequiredAttribute working for FKs? The reason I ask is that I if I add a property like:

           [Required]

           public virtual Venue Venue { get; set; }

    I would have expected the resulting FK column to be NOT nullable, but it is actually nullable. I can workaround it (by adding another VenueID property of type int), but I'd rather not if possible…

  24. Nufri says:

    It looks like the StoreNameAttribute and StoreIgnoreAttribute did,t make it to the CTP, or I am missing something?

  25. Thomas says:

    Is it possible to use these annotations in another language, e.g. F#?

  26. Guillaume says:

    +1 Nufri

    Where are the StoreNameAttribute and StoreIgnoreAttribute?

  27. georgesb says:

    @Matthew Wills

    I've run into the same issue re: the [Required] attribute on a foreign key property still resulting in a nullable DB column. If you override OnModelCreating in your context class and use the fluent API to specify that a Venue is required, the resulting foreign key column is indeed not nullable.

    modelBuilder.Entity<Dinner>.HasRequired(d => d.Venue).WithMany(v => v.Dinners);

    This makes a separate Dinner.VenueId property unnecessary, although having to define column attributes using both annotations and fluent API is obviously less than ideal.

  28. Peter says:

    I would definitely want to have the [Length] attribute.

  29. Rob Kent says:

    Using the MapSingleType method it seems that you have to remap the whole object. This is a pain if you just want to remap a single property. I would like to use data annotation to do this but the current CTP4 doesn’t seem to support it, or I cannot find the correct attibute to use. For example, with Data.Linq you can use the Column attribute with the Name property but there doesn’t seem to be an equivalent in EF. A lot of the attributes you mention above seem to be missing from the CTP4 – is that correct or have I missed something?

  30. Sunny says:

    How would you specify different data types for string ?

    Specially when you want to use text or ntext ?

    Cheers

    Sunny

  31. stmcdani says:

    Looking forward to StoreNameAttribute

  32. String type says:

    Defining the string type will be a blessing!

  33. Alex says:

    What about supporting DisplayAttribute? It's very important for localization. BTW what done for localization in EF4? In EF 3.5.1 we created own wrap of EntityModelCodeGenerator which translates LongDiscription from edmx metadata to DisplayName attribute of ComponentModel. And why localization attributes don't collected in one namespace and used all frameworks? ASP uses Display via MetadataType, WinForms uses DisplayName directly, RIA uses Display via MetadataType on server and directly on client. It's pain to support this especially if EF doesn't care about it. Thanks!

  34. Grant says:

    With respect to the proposed naming convention for [StoreInline] and [StoreIgnore], it appears most existing .NET attribute names conform to the convention "PropertyName is/has AttributeName".

    So we get "ID is Key" or "Name has Length(200)".  The current StoreXXX naming convention doesn't really apply this convention.  

    I would suggest attribute names such as [NotPersisted] and [PersistedInline], so the convention is maintained:  "InMemoryProperty is NotPersisted" or "MyComplexType is PersistedInline".

  35. Asher says:

    Hi,

    The last option:

    "Having data annotation attributes put CSDL annotations in your model that other systems (such as OData) can read."

    sounds grate to me. This can be leveraged by T4 templates to generate annotations with the self tracing entities and "close a circle" for development with Silverlight RIA. Generally, it would help in facilitating data annotation for non-code first scenarios (kind of looking on it from the other direction).

    Is it really in the pipeline or is it just a thought?

    Best,

    Asher

  36. David says:

    I'm devopping a CMS, and the system executes SQL scripts to create or modify the DB for each Version of the CMS. So if the DB contains version 1.0 and the CMS running is version 3.0 then the scripts for 2.0 and 3.0 are executed, so that no data in the DB is lost. If EF would have an attribute like the OptionalFieldAttribute with the VersionAdded parameter like in .NET serialization, the EF could modify the DB model accordingly withouth recreating the DB and loosing data. This way the CMS would not need any DB specific scripts and the code would be completely independent of a specific DB SQL dialect.

  37. Jack says:

    Don't mean to be rude but why would any right minded developer make it so the db columns are alphabetically sorted BY DEFAULT?

    Have you ever heard of the principle of least surprise?

    And the fact this BUG is still in here from CTP3 to CTP4 is astounding.

    Someone went out of their way to add a .OrderBy() clause somewhere in the code that is completely uncalled for.

    Judging by the EF teams responsive (or lack of) to the enum debacle I get the feeling this bug will be in here post release and maybe many years into the future.

  38. Josh Fuller says:

    Hi, I am still I getting the "unable to infer a primary key" error on any of the tables I try to access. I am using the [Key] attribute as you indicated, but it seems to have no effect. I also tried declaring the key in OnModelCreating in the DbContext. This at least gives me a different error: "Key expression is not valid." Has anyone else run into this? I'm finding very few examples of this error online. I'm using .NET 4, VisualStudio 2010, etc.

  39. Jon says:

    Is there a way to add composite keys?

    Example:

    [Key]

    orderNumber, orderDate

  40. dirk schomacker says:

    Hi,

    is it possible to mark a base class as something like "single inheritance" or "Ignore as own entity" . We have a layered szenario, in which baseclasses are the core-database-classes and they resides in a separate assembly.   The enhanced and derived classes resides in the main application. These concrete classes should be handled as single tables in the database. There is no further inheritance on the baseclasses (only one derived class). The best approach would be "TPC (Table per concrete Class)" , but it has configuration overhead and the concrete classes are hidden in the dbcontext. (only dbset with baseclass) . It seems to me, that it must be easy to implement, because there is only a single inheritance, so the classes can handled as classes without inheritance.    

    greetings, Dirk

  41. kirk palmer says:

    To give my 2 cents, I would love to see Default Value Annotation. I would also like a data annotation for setting the data column type for example a text column instead of varchar.

  42. rodrigo canales says:

    i love if EF can support uniqueidentifier PK (Guid), StoreGeneratedAttribute support store generated pattern like newsecuencialid or newid values

  43. Craig says:

    Yes, I'd like to be able to specify a string as non-unicode to map to varchar.

    I'm currently hitting an issue where SQL fails to compile a query using a unicode query parameter that EF is generating.

  44. Gustav1 says:

    It would be nice to mark a column as "optionally existing" to enable flexibility with legacy databases

  45. I would really like the unicode attribute. We have a big project about to start, and the entire project will require unicode support. Something like a unicode data annotation would go a long way.

  46. Martin Ross says:

    MinPrecision, MaxPrecision, Precision (to specify both or that they are the same) would be useful

    DefaultValue would be good

  47. Nikhil Jahagirdar says:

    Hi,

    what  is the namespace we need refer in order to add relateto[] attibute

  48. Eric says:

    Visit http://www.entityframeworktutorial.net to learn entity framework

  49. I've tried adding this says:

    And the key attribute does not work for me.

Skip to main content