新建一個控制檯應用程序,並安裝entityframework數據庫
新建一個文件Blog.cs類,輸入如下代碼:併發
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace DataAnnotations { public class Blog { [Key] public int PrimaryTrackingKey { get; set; } [Required] public string Title { get; set; } [MaxLength(50)] public string BloggerName { get; set; } [NotMapped] public string BlogCode { get { return Title.Substring(0, 1) + ":" + BloggerName.Substring(0, 1); } } } }
這個示例就是演示代碼中的4個標記,接下來生成DbContext類:app
using System.Data.Entity; namespace DataAnnotations { internal class TestContext : DbContext { public DbSet<Blog> Blogs { get; set; } } }
程序的執行文件Program.cs以下:ide
using System; namespace DataAnnotations { internal class Program { private static void Main(string[] args) { populate(); retreive(); Console.WriteLine("請按任意鍵結束!"); Console.ReadKey(); } private static void populate() { using (var context = new TestContext()) { var blog = new Blog { Title = "Hello World! ", BloggerName = "You are freshman." }; context.Blogs.Add(blog); context.SaveChanges(); } }//void private static void retreive() { using (var context = new TestContext()) { foreach (var blog in context.Blogs) { Console.WriteLine("{0}.Title = {1}, BloggerName = {2}", blog.PrimaryTrackingKey, blog.Title, blog.BloggerName); } } }//void } }
執行程序,並按任意鍵終止!ui
能夠在其生成的數據庫中找到Blogs表,表的建立代碼以下:spa
CREATE TABLE [dbo].[Blogs] ( [PrimaryTrackingKey] INT IDENTITY (1, 1) NOT NULL, [Title] NVARCHAR (MAX) NOT NULL, [BloggerName] NVARCHAR (50) NULL, CONSTRAINT [PK_dbo.Blogs] PRIMARY KEY CLUSTERED ([PrimaryTrackingKey] ASC) );
此代碼和Blog.cs代碼對照,能夠知道每一個標記的含義。[Key]是PRIMARY KEY,[Required]是NOT NULL,[MaxLength(50)]中的數字對應NVARCHAR(50)中的數字,[NotMapped]表示這個屬性不用保存在數據庫中。code
這裏要說明的是,整數類型的主鍵默認identity(1,1), string類型默認映射爲nvarchar(max)。blog
這個示例演示覆合主鍵與複合外鍵:排序
模型文件爲:ip
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace DataAnnotations { public class Passport { [Key] [Column(Order = 1)] [DatabaseGenerated(DatabaseGeneratedOption.None)] public int PassportNumber { get; set; } [Key] [Column(Order = 2)] public string IssuingCountry { get; set; } public DateTime Issued { get; set; } public DateTime Expires { get; set; } } public class PassportStamp { [Key] public int StampId { get; set; } public DateTime Stamped { get; set; } public string StampingCountry { get; set; } [ForeignKey(name: "Passport")] [Column(Order = 1)] public int PassportNumber { get; set; } [ForeignKey(name: "Passport")] [Column(Order = 2)] public string IssuingCountry { get; set; } public Passport Passport { get; set; } } }
生成的數據庫表的代碼爲:
CREATE TABLE [dbo].[Passports] ( [PassportNumber] INT NOT NULL, [IssuingCountry] NVARCHAR (128) NOT NULL, [Issued] DATETIME NOT NULL, [Expires] DATETIME NOT NULL, CONSTRAINT [PK_dbo.Passports] PRIMARY KEY CLUSTERED ([PassportNumber] ASC, [IssuingCountry] ASC) ); CREATE TABLE [dbo].[PassportStamps] ( [PassportNumber] INT NOT NULL, [IssuingCountry] NVARCHAR (128) NULL, [StampId] INT IDENTITY (1, 1) NOT NULL, [Stamped] DATETIME NOT NULL, [StampingCountry] NVARCHAR (MAX) NULL, CONSTRAINT [PK_dbo.PassportStamps] PRIMARY KEY CLUSTERED ([StampId] ASC), CONSTRAINT [FK_dbo.PassportStamps_dbo.Passports_PassportNumber_IssuingCountry] FOREIGN KEY ([PassportNumber], [IssuingCountry]) REFERENCES [dbo].[Passports] ([PassportNumber], [IssuingCountry]) ); GO CREATE NONCLUSTERED INDEX [IX_PassportNumber_IssuingCountry] ON [dbo].[PassportStamps]([PassportNumber] ASC, [IssuingCountry] ASC);
複合鍵的Order是按着大小排序,並非指序號。外鍵的順序要與主鍵對應列位置一致。Order值不必定要相等。
代碼中使用[DatabaseGenerated(DatabaseGeneratedOption.None)]關閉了整數類型主鍵的Identity特性。另外兩個選項爲Computed,Identity。
模型代碼
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace DataAnnotations { public class Blog { public int BlogId { get; set; } [Required] public string Title { get; set; } public BlogDetails BlogDetail { get; set; } } [ComplexType] public class BlogDetails { public DateTime? DateCreated { get; set; } [MaxLength(250)] public string Description { get; set; } } }
沒有主鍵,又沒有引用其餘實體的類爲ComplexType,這裏的標記是能夠省略的。上下文代碼
using System.Data.Entity; namespace DataAnnotations { internal class TestContext : DbContext { public DbSet<Blog> Blogs { get; set; } } }
上下文中只有Blog集合,沒有細節集合。填充與讀取代碼
private static void populate() { using (var context = new TestContext()) { var blog = new Blog { Title = "My First", BlogDetail = new BlogDetails { DateCreated = DateTime.Now, Description = "這裏省略10000字!" } }; context.Blogs.Add(blog); context.SaveChanges(); } }//void private static void retreive() { using (var context = new TestContext()) { foreach (var b in context.Blogs) { Console.WriteLine("{0}.{1}", b.BlogId, b.Title); var d = b.BlogDetail; Console.WriteLine("{0}.{1}", d.DateCreated, d.Description); } } }//void
數據庫表
CREATE TABLE [dbo].[Blogs] ( [BlogId] INT IDENTITY (1, 1) NOT NULL, [Title] NVARCHAR (MAX) NOT NULL, [BlogDetail_DateCreated] DATETIME NULL, [BlogDetail_Description] NVARCHAR (250) NULL, CONSTRAINT [PK_dbo.Blogs] PRIMARY KEY CLUSTERED ([BlogId] ASC) );
複雜類型將與引用他的實體一塊兒扁平到一個數據庫表中,默認的列名爲ComplexTypeName_PropertyName。
本例演示如何爲表和表中的列更名,修改列的數據類型,模型:
using System.ComponentModel.DataAnnotations.Schema; namespace DataAnnotations { [Table("InternalBlogs", Schema = "dbo")] public class Blog { public int BlogId { get; set; } [Column("BlogDescription", TypeName = "ntext")] public string Description { get; set; } } }
對應的數據庫表爲:
CREATE TABLE [dbo].[InternalBlogs] ( [BlogId] INT IDENTITY (1, 1) NOT NULL, [BlogDescription] NTEXT NULL, CONSTRAINT [PK_dbo.InternalBlogs] PRIMARY KEY CLUSTERED ([BlogId] ASC) );
可見,表的名稱,列的名稱與數據類型都發生的改變。
示例五
數據庫經過併發檢查和行版原本處理併發,模型代碼爲:
using System.ComponentModel.DataAnnotations; namespace DataAnnotations { public class Blog { public int BlogId { get; set; } [ConcurrencyCheck] public string BloggerName { get; set; } [Timestamp] public Byte[] TimeStamp { get; set; } } }
對應生成的數據庫表代碼爲:
CREATE TABLE [dbo].[Blogs] ( [BlogId] INT IDENTITY (1, 1) NOT NULL, [BloggerName] NVARCHAR (MAX) NULL, [TimeStamp] ROWVERSION NOT NULL, CONSTRAINT [PK_dbo.Blogs] PRIMARY KEY CLUSTERED ([BlogId] ASC) );
[Timestamp]對應生成了非空的行版本類型,標記了[ConcurrencyCheck]的BloggerName屬性會在生成的更新數據庫代碼的Where子句中添加併發檢查。
When SaveChanges is called, because of the ConcurrencyCheck annotation on the BloggerName 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 BloggerName.