Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / All-Topics

Database Related Attributes in Code First

4.33/5 (2 votes)
24 Mar 2014CPOL5 min read 9.3K  
This post is a follow-up on the post about Validation attributes in Code-First.

This post is a follow-up on the post about Validation attributes in Code-First. While validation attributes focus on making sure the data in the model is correct, the attributes listed here instead focus on instructing Entity Framework’s database generation engine how the database should be structured.

Column

Specify what column name to use for this class in the database.

C#
public class Customer
{
    [Column("CustomerFirstName")]
    public string FirstName { get; set; }
}

ConcurrencyCheck

Mark property as included in a value level optimistic concurrency check. This means that the property will be verified that it hasn’t changed before a new Update or Insert is performed. You need to mark all non-key properties, that you want to check, with this attribute.

C#
public class Customer
{
    public int Id { get; set; }

    [ConcurrencyCheck]
    public string Name { get; set; }

    [ConcurrencyCheck]
    public int Age { get; set; }

    [ConcurrencyCheck]
    public string City { get; set; }
}

If you have large tables, this can cause large where clauses also and thus slowing down your queries. This way of performing optimistic concurrency check is therefore not the suggested one. Instead, use the TimeStamp attribute to simply figure out if the row has been changed or not.

DatabaseGenerated

Indicates that this property is generated by the database (i.e., a TimeStamp or an automatically increased id) and that EF should leave it. There are three different options to choose from:

  • None – no value is generated
  • Identity – database creates an id when row is inserted
  • Computed – database calculates a value when a row is inserted or updated
C#
public class Customer
{
    public int Id { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime CreatedDate { get; set; }   // Date is set on server
}

ForeignKey

Used if a linked property and its foreign key id property are named in different ways. If the linked property is named SystemUser and the foreign key property is named SystemUserId (with only Id added at the end), then there’s no need for this attribute. In the example below, these Entity Framework naming conventions are not being followed and the ForeignKey attribute is needed for the User property.

C#
public class Customer
{
    [Key]
    public int CustomerId { get; set; }

    public int SystemUserId { get; set; }
    [ForeignKey("SystemUserId")]
    public virtual SystemUser User { get; set; }
}

InverseProperty

Specify back-reference in relationship when naming logic doesn’t apply. In the example below, the Customer class refers to SystemUser as User. For the SystemUser to be able to link to the correct property in Customer, you have to specify the name of the property using the InverseProperty attribute. If the Customer class would have referred to the user as SystemUser, then there wouldn’t be any need for adding this property.

C#
public class Customer
{
    [Key]
    public int CustomerId { get; set; }

    public int SystemUserId { get; set; }
    [ForeignKey("SystemUserId")]
    public virtual SystemUser User { get; set; }
}

public class SystemUser
{
    [Key]
    public int SystemUserId { get; set; }

    [InverseProperty("User")]
    public virtual IEnumerable<Customer> Customers { get; set; }
}

Key

Naming conventions for Entity Framework specify that the default name for the key property should be either Id or the class name combined with “Id” as in BlogId or CustomerId. If these conventions are used, then Entity Framework will be able to find the key property. But if you want to use a different name for the key of your class, you have to decorate it with the [Key] attribute, as in the following example.

C#
public class CrmCustomer
{
    [Key]
    public int CustomerId { get; set; }
}

MaxLength and StringLength

These attributes work for validation purposes, but they will also limit the size of the parameter’s field in the database. Besides the fact that StringLength also can specify a MinLength, they are practically identical. The reason why the new MaxLength attribute was added was because binary data can be stored as well and StringLength wrongly implies it has to be a string.

If a string is used without any size limitations, the database field gets the nvarchar(MAX) type where MAX = 4000. However, since nvarchar is used, the database field only uses the space it needs.

1 - NotSpecifyingStringLength

If we want to limit the maximum space used, we can use anyone of MaxLength and StringLength.

C#
public class Customer
{
    public int Id { get; set; }

    [MaxLength(40)]
    public string City { get; set; }

    [StringLength(40)]
    public string County { get; set; }

    [MaxLength(40)]
    public string Country { get; set; }
}

In the picture below, the max length is set to 40 for all strings. However, the city field was updated in the model from “no restriction” to [MaxLength(40)] and that didn’t have any effects on the database structure. This is due to the fact that shrinking the size of a field is potentially problematic and you might end up with lost data. This new size constraint is therefore only used internally in Entity Framework and not in the database storage.
2 - SpecifyingStringLength

The largest possible length of a string you can set is determined by the length of an Int32. To use that value, simply write:

C#
public class Comment
{
    [StringLength(Int32.MaxValue)]
    public string Text { get; set; }
}

MetadataType

This attribute is not used by Code-first, but rather by Model first where you’re able to add code-first attributes to a model-first created class. You can read more about it here.

NotMapped

Mark class/property as excluded from database storage. This is useful if you have a calculated or concatenated parameter, as in the example below.

C#
public class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    [NotMapped]
    public string FullName { get { return FirstName + " " + LastName; } }
}

Required

Mark field as required and that it can’t be null. This is also used as a validation attribute.

C#
public class Customer
{
    public int id { get; set; }
    [Required]
    public int age { get; set; }
}

ScaffoldColumn

Indicates if a column should be included in scaffolding or not.

C#
public class Data
{
    public int Id { get; set; }

    [ScaffoldColumn(false)]
    public int InternalData { get; set; }
}

Table

Specify what table name to use in database.

C#
[Table("CrmSystem_Customer")]
public class Customer
{
    [Key]
    public int CustomerId { get; set; }
}

TimeStamp

The TimeStamp attribute is used to enable Optimistic Concurrency Check in Entity Framework. A good overview on how to implement it can be found here. To use it, just add an extra byte array property to your class marked with the TimeStamp attribute, as shown here:

C#
public class Customer
{
    [Key]
    public int CustomerId { get; set; }

    [TimeStamp]
    public byte[] RowVersion { get; set; }    // For optimistic concurrency check
}

Validation Attributes

The following attributes are described in my post about validation attributes: Compare, CreditCard, CustomValidation, DataType, Display, DisplayFormat, EmailAddress, EnumDataType, FileExtensions, MaxLength, MembershipPassword, MinLength, Phone, RangeRegularExpression, Required, StringLength, UIHint and Url.

Attributes in DataAnnotations class not included here

  • Association
  • DisplayColumn – Used by DynamicData to specify what column to display as foreign key label, and how to sort (read more)
  • Editable – According to the manual, it indicates whether the user should be able to change the field’s value. There is no enforcing in MVC to make sure this is kept and it’s up to the programmer to use it internally.
  • ScaffoldTable – Used by ASP.NET Dynamic Data to decide whether a table should be scaffolded or not

More Resources

If you want to read more about DataAnnotations, I suggest the following links:

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)