[Table("Passport")]
public class Passport
{
[Key]
[DatabaseGenerated(DatabaseGenerationOption.Identity)]
[Column(Order=1)]
public int PassportNumber { get; set; }
[Key]
[Column(Order = 2)]
[Column("IssuingCountry", TypeName="NVARCHAR")]
public string IssuingCountry { get; set; }
[Required]
public DateTime Issued { get; set; }
public DateTime Expires { get; set; }
}
public class PassportStamp
{
[Key]
[DatabaseGenerated(DatabaseGenerationOption.Computed)]
public int StampId { get; set; }
public DateTime Stamped { get; set; }
[MaxLength(10), MinLength(5)]
public string StampingCountry { get; set; }
[ForeignKey("Passport")]
[Column(Order = 1)]
public int PassportNumber { get; set; }
[ForeignKey("Passport")]
[Column(Order = 2)]
public string IssuingCountry { get; set; }
public Passport Passport { get; set; }
[InverseProperty("CreatedBy")]
public List<Post> PostsWritten { get; set; }
[NotMapped]
public string Code => IssuingCountry.Substring(0, 1) + ":" + PassportNumber;
}
Complex Types
- It’s not uncommon to describe a domain entities across a set of classes and then layer those classes to describe a complete entity.
- For example, you may add a class called BlogDetails to describe Blog entity.
- In domain driven design, BlogDetails is referred to as a value object.
- Now you can add a property to the Blog class to represent the BlogDetails for that blog.
- Entity Framework refers to value objects as complex types.
- Complex types cannot be tracked on their own.
[ComplexType]
public class BlogDetails
{
public DateTime? DateCreated { get; set; }
[MaxLength(250)]
public string Description { get; set; }
}
Concurrency Check
- The
ConcurrencyCheck
annotation allows you to flag one or more properties to be used for concurrency checking in the database when a user edits or deletes an entity.
- When
SaveChanges
is called, because of the ConcurrencyCheck
annotation on the field, the original value of that property will be used in the update.
- The command will attempt to locate the correct row by filtering not only on the key value but also on the original value of entity.
- If someone has changed the field for that entity in the meantime, the update will fail and you’ll get a
DbUpdateConcurrencyException
that you'll need to handle.
[ConcurrencyCheck, MaxLength(10, ErrorMessage="BloggerName must be 10 characters or less"), MinLength(5)]
public string BloggerName { get; set; }
Time Stamp
- It's more common to use
rowversion
or timestamp
fields for concurrency checking.
- Rather than using the
ConcurrencyCheck
annotation, you can use the more specific TimeStamp
annotation as long as the type of the property is byte array.
- Code first will treat Timestamp properties the same as
ConcurrencyCheck
properties, but it will also ensure that the database field that code first generates is non-nullable.
- You can only have one timestamp property in a given class.
[Timestamp]
public Byte[] TimeStamp { get; set; }
Index Attribute