1. 程式人生 > >【配置屬性】—Entity Framework例項詳解(DataAnnotations and Fluent API)

【配置屬性】—Entity Framework例項詳解(DataAnnotations and Fluent API)

Entity Framework Code First modeling workflow allows you to use your own domain classes to represent the model which EF relies on to perform querying, change tracking and updating functions. Code first leverages a programming pattern referred to as convention over configuration. What this means is that code first will assume that your classes follow the conventions of the schema that EF uses for a conceptual model. In that case, EF will be able to work out the details it needs to do its job. However, if your classes do not follow those conventions, you have the ability to add configurations to your classes to provide EF with the information it needs.

Code first gives you two ways to add these configurations to your classes. One is using simple attributes called DataAnnotations and the other is using code first’s Fluent API, which provides you with a way to describe configurations imperatively, in code.

This article will focus on using DataAnnotations (in the System.ComponentModel.DataAnnotations namespace) to configure your classes – highlighting the most commonly needed configurations. DataAnnotations are also understood by a number of .NET applications, such as ASP.NET MVC which allows these applications to leverage the same annotations for client-side validations.

I’ll demonstrate code first DataAnnotations with a simple pair of classes: Blog and Post.

  1. public class Blog
  2.   {
  3.     public int Id { get; set; }
  4.     public string Title { get; set; }
  5.     public string BloggerName { get; set;}
  6.     public virtual ICollection<Post> Posts { get; set; }
  7.   }
  8.   public class
     Post
  9.   {
  10.     public int Id { get; set; }
  11.     public string Title { get; set; }
  12.     public DateTime DateCreated { get; set; }
  13.     public string Content { get; set; }
  14.     public int BlogId { get; set; }
  15.     public ICollection<Comment> Comments { get; set; }
  16.   }

You can read the whitepaper, Building an MVC 3 App with Code First and Entity Framework 4.1, which demonstrates using these classes with Entity Framework 4.1 Code First in an MVC 3 application. I’ll use the same application to demonstrate Data Annotations in action.

As they are, the Blog and Post classes conveniently follow code first convention and required no tweaks to help EF work with them. But you can also use the annotations to provide more information to EF (and to MVC 3) about the classes and the database that they map to.

Key

Entity Framework relies on every entity having a key value (aka EntityKey) that it uses for tracking entities. One of the conventions that code first depends on is how it implies which property is the key in each of the code first classes. That convention is to look for a property named “Id” or one that combines the class name and “Id”, such as “BlogId”. In addition to EF’s use of the EntityKey, the property will map to a primary key column in the database.

The Blog and Post classes both follow this convention. But what if they didn’t? What if Blog used the namePrimaryTrackingKey instead or even foo? If code first does not find a property that matches this convention it will throw an exception because of Entity Framework’s requirement that you must have a key property. You can use the key annotation to specify which property is to be used as the EntityKey.

  1. public class Blog
  2.   {
  3.     [Key]
  4.     public int PrimaryTrackingKey { get; set; }
  5.     public string Title { get; set; }
  6.     public string BloggerName { get; set;}
  7.     public virtual ICollection<Post> Posts { get; set; }
  8.   }

If you are using code first’s database generation feature, the Blog table will have a primary key column named PrimaryTrackingKey which is also defined as an IdentityKey by default.


Required

The Required annotation tells EF that a particular property is required.

Adding Required to the Title property will force EF and MVC to ensure that the property has data in it.

  1. [Required]
  2. public string Title { get; set; }

With no additional no code or markup changes in the application, my existing MVC application will perform client side validation, even dynamically building a message using the property and annotation names.


Figure 1

With MVC’s client-side validation feature turned off, you will get the same response, except that it will be a result of server-side validation. Entity Framework will perform the validation on the Required annotation and return the error to MVC which will display the message.

The Required attribute will also affect the generated database by making the mapped property non-nullable. Notice that the Title field has changed to “not null”.


MaxLength and MinLength

The MaxLength and MinLength attributes allow you to specify additional property validations, just as you did with Required.

Here is the BloggerName with length requirements. The example also demonstrates how to combine attributes.

  1. [MaxLength(10),MinLength(5)]
  2.       public string BloggerName { get; set; }

The MaxLength annotation will impact the database by setting the property’s length to 10. Prior to that, the default length was 128 as is the length of Title.


MVC 3 client-side annotation and EF 4.1 server-side annotation will both honor this validation, again dynamically building an error message: “The field BloggerName must be a string or array type with a maximum length of '10'.” That message is a little long. Many annotations let you specify an error message with the ErrorMessage attribute.

  1. [MaxLength(10, ErrorMessage="BloggerName must be 10 characters or less"),MinLength(5)]
  2. public string BloggerName { get; set; }

You can also specify ErrorMessage in the Required annotation.


Figure 2

NotMapped

Code first convention dictates that every property is represented in the database. But this isn’t always the case in your applications. For example you might have a property in the Blog class that creates a code based on the Title and BloggerName fields. That property can be created dynamically and does not need to be stored. You can mark any properties that do not map to the database with the NotMapped annotation such as this BlogCode property.

  1. [NotMapped]
  2.         public string BlogCode{
  3.             get{
  4.                 return Title.Substring(01) + ":" + BloggerName.Substring(01);
  5.             }
  6.         }

ComplexType

It’s not uncommon to describe your 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 your model.

  1. public class BlogDetails
  2.     {
  3.         public DateTime? DateCreated { get; set; }
  4.         [MaxLength(250)]
  5.         public string Description { get; set; }
  6.     }

Notice that BlogDetails does not have any type of key property. In domain driven design, BlogDetails is referred to as a value object. Entity Framework refers to value objects as complex types.  Complex types cannot be tracked on their own.

However as a property in the Blog class, BlogDetails it will be tracked as part of a Blog object. In order for code first to recognize this, you must mark the BlogDetails class as a ComplexType.

  1. [ComplexType]
  2.     public class BlogDetails
  3.     {
  4.         public DateTime? DateCreated { get; set; }
  5.         [MaxLength(250)]
  6.         public string Description { get; set; }
  7.     }

Now you can add a property in the Blog class to represent the BlogDetails for that blog.

    public BlogDetails BlogDetail { get; set; }

In the database, the Blog table will contain all of the properties of the blog include the properties contained in its BlogDetail property. By default, each one is preceded with the name of the complex type, BlogDetail, as you can see in Figure 3.


Figure 3: The Blogs database table containing columns that map to a complex type

Another interesting note is that although the DateCreated property was defined as a non-nullable DateTime in the class, the relevant database field is nullable. You must use the Required annotation if you wish to affect the database schema.

ConcurrencyCheck

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. If you've been working with Entity Data Model, this aligns with setting a property's ConcurrencyMode to Fixed.

Let’s see how ConcurrencyCheck works by adding it to the BloggerName property.

  1. [ConcurrencyCheck,
  2.  MaxLength(10, ErrorMessage="BloggerName must be 10 characters or less"),
  3.  MinLength(5)]
  4. public string BloggerName { get; set; }

Concurrency checking depends on having access to the original value of the property. If the context instance that originally queried for a blog stays in memory, it will retain knowledge of the original values of the blog along with its current values. But in a disconnected application, such as the MVC application being used, you’ll need to remind the context of that original value.

You can do that using this db.entry property method before calling SaveChanges. In the following Edit postback method of the sample MVC application, the UI has returned the original value of the blogger name in the originalName parameter. Then it is applied to the DbContext’s tracking entry by setting the Property’s OriginalValue as you can see in the line of code just before SaveChanges is called.

  1. [HttpPost]
  2.         public ActionResult Edit(int id, string originalName, Blog blog)
  3.         {
  4.             try
  5.             {
  6.                 db.Entry(blog).State = System.Data.EntityState.Modified;
  7.                 db.Entry(blog).Property(b => b.BloggerName).OriginalValue = originalName;
  8.                 db.SaveChanges();
  9.                 return RedirectToAction("Index");
  10.             }
  11.             catch
  12.             {
  13.                 return View();
  14.             }
  15.         }

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.  Here are the critical parts of the UPDATE command sent to the database, where you can see the command will update the row that has a PrimaryTrackingKey is 1 and a BloggerName of “Julie” which was the original value when that blog was retrieved from the database.

  1. where (([PrimaryTrackingKey] = @4) and ([BloggerName] = @5))
  2. @4=1,@5=N'Julie'

If someone has changed the blogger name for that blog in the meantime, this update will fail and you’ll get a DbUpdateConcurrencyException that you'll need to handle.

TimeStamp

It's more common to use rowversion or timestamp fields for concurrency checking. But 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.

Adding the following property to the Blog class:

  1. [Timestamp]
  2.         public Byte[] TimeStamp { get; set; }

results in code first creating a non-nullable timestamp column in the database table.


Table and Column

You can also use code first with an existing database. But it's not always the case that the names of the classes and properties in your domain match the names of the tables and columns in your database.

My class is named Blog and by convention, code first presumes this will map to a table named Blogs. If that's not the case you can specify the name of the table with the Table attribute. Here for example, the annotation is specifying that the table name is InternalBlogs.

  1. [Table("InternalBlogs")]
  2.    public class Blog

You can also use the Table attribute when code first is creating the database for you if you simply want the table name to be different than the convention.

The Column annotation is a more adept in specifying the attributes of a mapped column. You can stipulate a name, data type or even the order in which a column appears in the table. Here is an example of the Column attribute.

  1. [Column(“BlogDescription", TypeName="ntext")]
  2.    public String Description {get;set;}

Don’t confuse Column’s TypeName attribute with the DataType DataAnnotation. DataType is an annotation used for the UI and is ignored by code first.

Here is the table after it’s been regenerated. The table name has changed to InternalBlogs and Description column from the complex type is now BlogDescription. Because the name was specified in the annotation, code first will not use the convention of starting the column name with the name of the complex type.


DatabaseGenerated

An important database features is the ability to have computed properties. If you're mapping your code first classes to tables that contain computed properties, you don't want Entity Framework to try to update those columns. But you do want EF to return those values from the database after you've inserted or updated data. You can use the DatabaseGenerated annotation to flag those properties in your class along with the Computed enum. Other enums are None and Identity.

  1. [DatabaseGenerated(DatabaseGenerationOption.Computed)]
  2.      public DateTime DateCreated { get; set; }

You can use database generated on byte or timestamp columns when code first is generating the database, otherwise you should only use this when pointing to existing databases because code first won't be able to determine the formula for the computed column.

You read above that by default, a key property will become an identity key in the database. That would be the same as setting DatabaseGenerated to DatabaseGenerationOption.Identity. If you do not want it to be an identity key, you can set the value to DatabaseGenerationOption.None.

Relationship Attributes: InverseProperty and ForeignKey

Code first convention will take care of the most common relationships in your model, but there are some cases where it needs help.

Changing the name of the key property in the Blog class created a problem with its relationship to Post. 

When generating the database, code first sees the BlogId property in the Post class and recognizes it, by the convention that it matches a class name plus “Id”, as a foreign key to the Blog class. But there is no BlogId property in the blog class. The solution for this is to create a navigation property in the Post and use the Foreign DataAnnotation to help code first understand how to build the relationship between the two classes —using the Post.BlogId property — as well as how to specify constraints in the database.

  1. public class Post
  2.     {
  3.         public int Id { get; set; }
  4.         public string Title { get; set; }
  5.         public DateTime DateCreated { get; set; }
  6.         public string Content { get; set; }
  7.         public int BlogId { get; set; }
  8.         [ForeignKey("BlogId")]
  9.         public Blog Blog { get; set; }
  10.         public ICollection<Comment> Comments { get; set; }
  11.     }

Figure 4 shows the constraint in the database that creates a relationship between InternalBlogs.PrimaryTrackingKey and Posts.BlogId. 


Figure 4

The InverseProperty is used when you have multiple relationships between classes.

In the Post class, you may want to keep track of who wrote a blog post as well as who edited it. Here are two new navigation properties for the Post class.

  1. public Person CreatedBy { get; set; }
  2.         public Person UpdatedBy { get; set; }

You’ll also need to add in the Person class referenced by these properties. The Person class has navigation properties back to the Post, one for all of the posts written by the person and one for all of the posts updated by that person.

  1. public class Person
  2.     {
  3.         public int Id { get; set; }
  4.         public string Name { get; set; }
  5.         public List<Post> PostsWritten { get; set; }
  6.         public List<Post> PostsUpdated { get; set; }
  7.     }

Code first is not able to match up the properties in the two classes on its own. The database table for Posts should have one foreign key for the CreatedBy person and one for the UpdatedBy person but code first will create four will foreign key properties: Person_Id, Person_Id1, CreatedBy_Id and UpdatedBy_Id.


To fix these problems, you can use the InverseProperty annotation to specify the alignment of the properties.

  1. [InverseProperty("CreatedBy")]
  2.         public List<Post> PostsWritten { get; set; }
  3.         [InverseProperty("UpdatedBy")]
  4.         public List<Post> PostsUpdated { get; set; }

Because the PostsWritten property in Person knows that this refers to the Post type, it will build the relationship to Post.CreatedBy. Similarly, PostsUpdated will be connected to Post.UpdatedBy. And code first will not create the extra foreign keys.


Summary

DataAnnotations not only let you describe client and server side validation in your code first classes, but they also allow you to enhance and even correct the assumptions that code first will make about your classes based on its conventions. With DataAnnotations you can not only drive database schema generation, but you can also map your code first classes to a pre-existing database.

While they are very flexible, keep in mind that DataAnnotations provide only the most commonly needed configuration changes you can make on your code first classes. To configure your classes for some of the edge cases, you should look to the alternate configuration mechanism, code first’s Fluent API .

About the Author

Julie Lerman is a Microsoft MVP, .NET mentor and consultant who lives in the hills of Vermont. You can find her presenting on data access and other Microsoft .NET topics at user groups and conferences around the world. Julie blogs at thedatafarm.com/blog and is the author of the highly acclaimed book, “Programming Entity Framework” (O’Reilly Media, 2009). Follow her on Twitter.com: julielerman.

Entity Framework Code First的預設行為是使用一系列約定將POCO類對映到表。然而,有時候,不能也不想遵循這些約定,那就需要重寫它們。重寫預設約定有兩種方式:Data Annotations和FluentAPI。Data Annotations在功能上是Fluent API的子集,在一些對映場景下使用Annotations不能達到重寫的目的,因此本篇文章中使用Fluent API配置屬性。

一、Fluent API配置屬性

Code First Fluent API通常情況下是在DbContext的派生類中重寫OnModelCreating方法。

1.配置Length

Length用來描述陣列的長度,當前包括string和Byte陣列。

預設約定Code First對string或byte陣列的預設長度約定是max。注意:Sql Server Compact中預設最大陣列長度是4000。

重寫約定使用HasMaxLength(nn),引數為可空整數。

<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">   1:  </span>Property(t => t.Name).HasMaxLength(50);

另外關於Length的Fluent API還有下面2個:

IsFixedLength(),配置屬性為固定長度。

IsMaxLength(),配置屬性為資料庫提供程式允許的最大長度。

2.配置Data Type

Data Type表示將.NET型別對映到的資料庫的資料型別。

預設約定:列的資料型別由使用的資料庫提供程式決定。以SQL Server為例:String->nvarchar(max),Integer->int,Byte[]->varbinary(max),Boolean->bit。

重寫約定:使用HasColumnType(“xxx”),下面列子的Photo是byte[]型別,配置對映到image資料型別:

<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">   1:  </span>Property(t => t.Photo).HasColumnType(<span class="str" style="margin: 0px; padding: 0px;">"image"</span>);

3.配置允許為空和不允許為空

預設約定:主鍵屬性不允許為空,引用型別(String,array)允許為空,值型別(所有的數字型別,Datetime,bool,char)不允許為空,可空的值型別Nullable<T>允許為空。

重寫約定:使用IsRequired()配置不允許為空,使用IsOptional()配置允許為空。下面配置Name屬性為不為空:

<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">   1:  </span> Property(t => t.Name).IsRequired();

4.配置屬性到指定列

預設約定:對映到與屬性名相同的列。

重寫約定:使用Property(t=>t.屬性名).HasColumnName(“xxx”)。下面配置Name對映到DepartmentName:

<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">   1:  </span>Property(t => t.Name).HasColumnName(<span class="str" style="margin: 0px; padding: 0px;">"DepartmentName"</span>);

5.配置主鍵

預設約定:(1)屬性名為ID或Id的預設為主鍵 

                (2)類名+ID或類名+Id預設為主鍵  (其中ID或Id的優先順序大於類名+ID或類名+Id)

重寫約定:使用HasKey(t=>t.屬性名)。下面將BlogId配置為主鍵:

<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">   1:  </span> HasKey(t => t.BlogId);

6.配置組合主鍵

下面的例子將DepartmentId和Name屬性組合作為Department型別的主鍵:

<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">   1:  </span>HasKey(t => <span class="kwrd" style="margin: 0px; padding: 0px;">new</span> { t.DepartmentId, t.Name });

7.配置Database-Generated

預設約定:整型鍵:Identity。

重寫約定:使用Property(t => t.屬性名).HasDatabaseGeneratedOption(DatabaseGeneratedOption)。

DatabaseGeneratedOption列舉包括三個成員:

(1) None:資料庫不生成值

(2) Identity:當插入行時,資料庫生成值

(3) Computed:當插入或更新行時,資料庫生成值

整型預設是Identity,資料庫生成值,自動增長,如果不想資料庫自動生成值,使用DatabaseGeneratedOption.None。

Guid型別作為主鍵時,要顯示配置為DatabaseGeneratedOption.Identity。

8.配置TimeStamp/RowVersion的樂觀併發

預設約定:這個沒有預設約定。

配      置:使用Property(t=>t.屬性名).IsRowVersion()

<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">   1:  </span>Property(t => t.RowVersion).IsRowVersion();

9.不配置TimeStamp的樂觀併發

有些資料庫不支援RowVersion型別,但是又想對資料庫的一個或多個欄位併發檢查,這時可以使用Property(t=>t.屬性名).IsConcurrencyToken(),下面的例子將SocialSecurityNumber配置為併發檢查。

<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">   1:  </span>Property(t => t.SocialSecurityNumber).IsConcurrencyToken();

10.配置String屬性是否支援Unicode內容

預設約定:預設string是Unicode(在SQL Server中是nvarchar)的。

重寫約定:下面的例子使用IsUnicode()方法將Name屬性配置為varchar型別的。

<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">   1:  </span>Property(t => t.Name).IsUnicode(<span class="kwrd" style="margin: 0px; padding: 0px;">false</span>);

11.配置小數的精度和小數位數

預設約定:小數是(18,2)

配      置:使用Property(t=>t.屬性名).HasPrecision(n,n)

<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">   1:  </span><span class="kwrd" style="margin: 0px; padding: 0px;">public</span> <span class="kwrd" style="margin: 0px; padding: 0px;">decimal</span> MilesFromNearestAirport { get; set; }

12.複雜型別

預設複雜型別有以下規則:

(1) 複雜型別沒有主鍵屬性 
(2) 複雜型別只能包含原始屬性。 
(3)在其他類中使用複雜型別時,必須表示為非集合型別。

使用DbModelBuilder.ComplexType方法顯示配置為複雜型別:

<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">   1:  </span>modelBuilder.ComplexType<Address>();

13.巢狀的複雜型別

巢狀的複雜型別只需顯示配置外層,內層自動繼承複雜型別的約定。

14.配置複雜型別的屬性

配置複雜型別的屬性和配置實體屬性一樣,具體參考下面的例項。

二、配置屬性例項

下面直接給出程式碼,程式碼上都有註釋。注:下面的實體主要是為了演示用

<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">   1:  </span>    <span class="rem" style="margin: 0px; padding: 0px;">//實體</span>
   2:      public class Trip
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">   3:  </span>    {
   4:          public Guid Identifier { get; set; }
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">   5:  </span>        <span class="kwrd" style="margin: 0px; padding: 0px;">public</span> DateTime StartDate { get; set; }
   6:          public DateTime EndDate { get; set; }
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">   7:  </span>        <span class="kwrd" style="margin: 0px; padding: 0px;">public</span> <span class="kwrd" style="margin: 0px; padding: 0px;">decimal</span> CostUSD { get; set; }
   8:          public string Description { get; set; }
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">   9:  </span>        <span class="kwrd" style="margin: 0px; padding: 0px;">public</span> <span class="kwrd" style="margin: 0px; padding: 0px;">byte</span>[] RowVersion { get; set; }
  10:      }
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  11:  </span> 
  12:      //複雜型別
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  13:  </span>    <span class="kwrd" style="margin: 0px; padding: 0px;">public</span> <span class="kwrd" style="margin: 0px; padding: 0px;">class</span> Address
  14:      {
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  15:  </span>        <span class="kwrd" style="margin: 0px; padding: 0px;">public</span> <span class="kwrd" style="margin: 0px; padding: 0px;">int</span> AddressId { get; set; }
  16:          public string StreetAddress { get; set; }
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  17:  </span>        <span class="kwrd" style="margin: 0px; padding: 0px;">public</span> <span class="kwrd" style="margin: 0px; padding: 0px;">string</span> City { get; set; }
  18:          public string State { get; set; }
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  19:  </span>        <span class="kwrd" style="margin: 0px; padding: 0px;">public</span> <span class="kwrd" style="margin: 0px; padding: 0px;">string</span> ZipCode { get; set; }
  20:      }
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  21:  </span> 
  22:      //複雜型別
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  23:  </span>    <span class="kwrd" style="margin: 0px; padding: 0px;">public</span> <span class="kwrd" style="margin: 0px; padding: 0px;">class</span> PersonalInfo
  24:      {
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  25:  </span>        <span class="kwrd" style="margin: 0px; padding: 0px;">public</span> Measurement Weight { get; set; }
  26:          public Measurement Height { get; set; }
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  27:  </span>        <span class="kwrd" style="margin: 0px; padding: 0px;">public</span> <span class="kwrd" style="margin: 0px; padding: 0px;">string</span> DietryRestrictions { get; set; }
  28:      }
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  29:  </span> 
  30:      //複雜型別
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  31:  </span>    <span class="kwrd" style="margin: 0px; padding: 0px;">public</span> <span class="kwrd" style="margin: 0px; padding: 0px;">class</span> Measurement
  32:      {
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  33:  </span>        <span class="kwrd" style="margin: 0px; padding: 0px;">public</span> <span class="kwrd" style="margin: 0px; padding: 0px;">decimal</span> Reading { get; set; }
  34:          public string Units { get; set; }
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  35:  </span>    }
  36:   
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  37:  </span>    <span class="rem" style="margin: 0px; padding: 0px;">//實體</span>
  38:      public class Person
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  39:  </span>    {
  40:          public Person()
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  41:  </span>        {
  42:              Address = new Address();
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  43:  </span>            Info = <span class="kwrd" style="margin: 0px; padding: 0px;">new</span> PersonalInfo()
  44:              {
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  45:  </span>                Weight = <span class="kwrd" style="margin: 0px; padding: 0px;">new</span> Measurement(),
  46:                  Height = new Measurement()
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  47:  </span>            };
  48:          }
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  49:  </span> 
  50:          public int PersonId { get; set; }
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  51:  </span>        <span class="kwrd" style="margin: 0px; padding: 0px;">public</span> <span class="kwrd" style="margin: 0px; padding: 0px;">int</span> SocialSecurityNumber { get; set; }
  52:          public string FirstName { get; set; }
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  53:  </span>        <span class="kwrd" style="margin: 0px; padding: 0px;">public</span> <span class="kwrd" style="margin: 0px; padding: 0px;">string</span> LastName { get; set; }
  54:          public Address Address { get; set; }
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  55:  </span>        <span class="kwrd" style="margin: 0px; padding: 0px;">public</span> <span class="kwrd" style="margin: 0px; padding: 0px;">byte</span>[] Photo { get; set; }
  56:          public PersonalInfo Info { get; set; }
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  57:  </span>        <span class="kwrd" style="margin: 0px; padding: 0px;">public</span> <span class="kwrd" style="margin: 0px; padding: 0px;">byte</span>[] RowVersion { get; set; }
  58:      }
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  59:  </span> 
  60:      //對實體Trip的配置,繼承自EntityTypeConfiguration<T>
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  61:  </span>    <span class="kwrd" style="margin: 0px; padding: 0px;">public</span> <span class="kwrd" style="margin: 0px; padding: 0px;">class</span> TripConfiguration : EntityTypeConfiguration<Trip>
  62:      {
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  63:  </span>        <span class="kwrd" style="margin: 0px; padding: 0px;">public</span> TripConfiguration()
  64:          {
<span class="lnum" style="color: rgb(96, 96, 96); margin: 0px; padding: 0px;">  65:  </span>            <span class="rem" style="margin: 0px; padding: 0px;">//配置Identifier對映到TripId列,並設為主鍵,且預設值為newid()</span>
  66:              HasKey(t => t.Identifier).Property(t => t.Identifier).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).HasColumnName("TripId");
            
           

相關推薦

配置屬性Entity Framework例項DataAnnotations and Fluent API

Entity Framework Code First modeling workflow allows you to use your own domain classes to represent the model which EF relies on to pe

配置屬性Entity Framework例項

Entity Framework Code First的預設行為是使用一系列約定將POCO類對映到表。然而,有時候,不能也不想遵循這些約定,那就需要重寫它們。重寫預設約定有兩種方式:Data Annotations和FluentAPI。Data Annotations

遷移Entity Framework例項

 好久沒有在部落格園更新部落格了,如今都換了新公司。前段時間寫了關於EF遷移的文件,今天拿出來作為這個系列的一篇吧。 一、Entity Framework 遷移命令(get-help EntityFramework) Enable-Migrations 啟用遷移 Add-Migration 為掛起的Mo

Spring MVCHandlerMapping初始化超詳細過程原始碼分析

Spring MVC的Control主要由HandlerMapping和HandlerAdapter兩個元件提供。HandlerMapping負責對映使用者的URL和對應的處理類,HandlerMapping並沒有規定這個URL與應用的處理類如何對映,在HandlerMapp

視頻Entity Framework Core 2.* 入門教程

數據 mode .com video work 查詢 刪除 page player 視頻專輯在B站上:https://www.bilibili.com/video/av34462368/ 內容暫時如下,還在更新中: 1. 簡介 & 創建Model,生成數據

PHP系列PHP組件

命令行 分享 .cn .com function package etc quest 說我 緣起 楓爺之前做過幾年的PHP的研發,大部分都是在開源框架的引導下,編寫代碼。現在依然,本能的會去讓我使用某個PHP框架開發PHP應用,也是因為懶吧,沒有好好的去研究研究除了框架之外

轉:HDFS基礎HDFS檔案目錄

版權宣告:本文為博主原創文章,若轉載,請註明出處,謝謝!    https://blog.csdn.net/baiye_xing/article/details/76268495 HDFS的檔案目錄圖 分析:從上圖可以看出,HDFS的檔案目錄主要由NameNode

linuxValgrind工具集十五:Callgrind效能分析圖

一、概述 1、Callgrind Callgrind用於記錄程式中函式之間的呼叫歷史資訊,對程式效能分析。預設情況下,收集的資料包括執行的指令數,它們與原始碼行的關係,函式之間的呼叫者、被呼叫者關係以及此類呼叫的數量。可選項是,對快取記憶體模擬和分支預測(類似於Cachegrin

linuxValgrind工具集十四:Cachegrind快取和分支預測分析器

一、概述 Cachegrind,它模擬CPU中的一級快取I1,Dl和二級快取,能夠精確地指出程式中cache的丟失和命中。如果需要,它還能夠為我們提供cache丟失次數,記憶體引用次數,以及每行程式碼,每個函式,每個模組,整個程式產生的指令數。這對優化程式有很大的幫助。 Cach

linuxValgrind工具集十三:DRD執行緒錯誤檢測器

一、概述 多執行緒程式設計需要注意的問題: 資料競爭;鎖競爭;POSIX執行緒API使用不當;死鎖; 二、使用 1、例子main.c原始碼 #include <stdio.h> #include <pthread.h> #include <s

linuxValgrind工具集十三:Helgrind執行緒錯誤檢測器

一、概述 Helgrind用於檢測C、C ++和Fortran程式中使用符合POSIX標準的執行緒函式造成的同步錯誤。 POSIX中關於執行緒的主要抽象描述有:共享公共地址空間的一組執行緒、執行緒建立、執行緒連線、執行緒退出、互斥(鎖)、條件變數(執行緒間事件通知)、讀寫器鎖、自

linuxValgrind工具集十二:DHAT:動態堆分析器

一、概述 DHAT動態堆分析器。Massif(堆分析器)是在程式結束後輸出分析結果,而DHAT是實時輸出結果,所以叫做動態堆分析器。Massif只記錄堆記憶體的申請和釋放,DHAT還會分析堆空間的使用率、使用週期等資訊。 DHAT的功能:它首先記錄在堆上分配的塊,通過分析每次記憶體訪

linuxValgrind工具集十一:Massif堆分析器

一、概述 Massif是一個堆分析器。它統計程式使用的堆記憶體大小(由malloc等函式分配的記憶體)。預設情況下不統計程式所使用的所有記憶體,如果想統計所有記憶體,需要使用選項–pages-as-heap=yes。 堆分析可以幫助減少程式使用的記憶體。如果分配的記憶體還沒有釋放

linuxValgrind工具集:SGCheck檢查棧和全域性陣列溢位

一、概述 SGCheck是一種用於檢查棧中和全域性陣列溢位的工具。它的工作原理是使用一種啟發式方法,該方法源於對可能的堆疊形式和全域性陣列訪問的觀察。 棧中的資料:例如函式內宣告陣列int a[10],而不是malloc分配的,malloc分配的記憶體是在堆中。 SGCheck和Me

linuxValgrind工具集:Memcheck檢查的內容和方法

一、值的有效性 1、什麼是值的有效性? 英文原文是Valid-value (V) bits,直譯過來就是有效值(V)位。 我將它理解為值的有效性,就是判斷在記憶體或CPU的實體地址中儲存的資料是否有效,比如在記憶體中變數(int i)代表的物理位置(不是地址),沒有初始化,就去使用它

linuxValgrind工具集:Memcheck命令列引數

【linux】Valgrind工具集詳解(五):命令列詳解中不夠全,在此專門針對Memcheck工具中的命令列引數做一次詳細的解釋。 Memcheck命令列選項 –leak-check=<no|summary|yes|full> [default: summary]

linuxValgrind工具集:Memcheck記憶體錯誤檢測器

一、概述 Memcheck是一個記憶體錯誤檢測器。它可以檢測C和C ++程式中常見的以下問題: 1、非法記憶體:如越界、釋放後繼續訪問; 2、使用未初始化的值; 3、釋放記憶體錯誤:如double-free(同一記憶體上執行了兩次free)、或者 malloc、new、new[] 與

linuxValgrind工具集:使用Valgrind gdbserver和GDB除錯程式

一、概述 在Valgrind下執行的程式不是由CPU直接執行的。相反,它執行在Valgrind提供的合成CPU上。這就是偵錯程式在Valgrind上執行時無法除錯程式的原因。 二、快速入門 在使用Memcheck工具時使用GDB除錯程式,啟動方式如下: 1、valgrind

linuxValgrind工具集:命令列

一、使用方法 usage: valgrind [options] prog-and-args 使用方法:valgrind [引數選項] 程式和引數 二、選擇工具 tool-selection option, with default in [ ]: 工具選擇選項,預設值在[]

基本操作樹上啟發式合併の

樹上啟發式合併是某些神仙題目的常見操作。 這裡有一個講得詳細一點的,不過為了深刻記憶,我還是再給自己講一遍吧!   DSU(Disjoint Set Union),別看英文名挺高階,其實它就是並查集…… DSU on tree,也就是樹上的啟發式合併(眾所周知,並查集最重要的優化就是啟發式合