EntityFramework Core 學習系列(一)Creating Model


EntityFramework Core 學習系列(一)Creating Model

Getting Started

使用Command Line 來添加 Package

dotnet add package Microsoft.EntityFrameworkCore.SqlServer 使用 -v 可以指定相應包的版本號。

使用dotnet ef 命令

 需要在.csproj 文件中包含下面引用

<ItemGroup>
	<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0"/>
</ItemGroup>

Creating a Model

Fluent API

 在繼承至 DbContext 的子類中,重載 OnModelCreating() 方法進行Fluent API 的配置。

public class MyDbContext : DbContext
{
	//...
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
    	modelBuilder.Entity<TEntity>()
    		.Property(b => b.Url)
    		.IsRequired();
    	//...
    }
    //...
}

Data Annotation

 或者可以使用數據注解直接在實體中進行配置:

public class Blogs
{
  	public string BlogName { get; set; }
  	[Required]
  	public string Url { get; set; }
}

關於配置的順序規范,

Fluent API > Data Annotations > Conventions

Include & Exclude

 有下列三種情況類或實體會被包含:

  1. By convention, types that are exposed in DbSet properties on your context are included in your model.
  2. Types that are mentioned in the OnModelCreating method are also included.
  3. Any types that are found by recursively exploring the navigation properties of discovered types are also included in the model.

你可以通過 Data Annotation 或者 Fluent API 來 排除包含,示例如下:

//Data Annotations Example Below:
public class Blogs
{
  public int BlogId { get; set;}
  
  public BlogAuthor BlogAuthors { get; set;}
}

[NotMapped]
public class BlogAuthor
{
  public string FirstName { get; set;}
  //...
}

//Fluent API Example Below:
public class MyDbContext : DbContext
{
	public DbSet<Blog> Blogs { get; set;}
	
	protected override OnModelCreating(ModelBuilder modelBuilder)
    {
    	modelBuilder.Ignore<BlogAuthor>();
    }
}
public class Blogs
{
  public int BlogId { get; set;}
  
  public BlogAuthor BlogAuthors { get; set;}
}

public class BlogAuthor
{
  public string FirstName { get; set;}
  //...
}

當然除了可以排出/包含類之外, 還可以自己配置相應的屬性如下:

//Data Annotations Example Below:
public class Blogs
{
  public int BlogId { get; set;}
  
  public BlogAuthor BlogAuthors { get; set;}
  
  [NotMapped]
  public DateTime BlogAddedTime { get; set;}
}

//Fluent API Example Below:
public class MyDbContext : DbContext
{
	public DbSet<Blog> Blogs { get; set;}
	
	protected override OnModelCreating(ModelBuilder modelBuilder)
    {
    	modelBuilder.Entity<Blog>()
    		.Ignore(b => b.BlogAddedTime);
    }
}
public class Blogs
{
  public int BlogId { get; set;}
  
  public BlogAuthor BlogAuthors { get; set;}
  
  public DateTime BlogAddedTime { get; set;}
}

Key

 關於EF Core 中的Key, 按照規范,如果一個屬性命名為Id 或者 以Id結尾的都會被配置成該實體的主鍵。比如下面的這個:

public class TestClass
{
  public int Id { get; set; }
  
  //or
  public int MyId { get; set; }
}

或者你可以按照 Data Annotation 或者 Fluent API 來進行配置:

// Data Annotations
public class Car 
{
  [Key]
  public string CarLicense { get; set; }
  
  public string CarFrameCode { get; set;}
}

//Fluent API
//...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  modelBuilder.Entity<Car>()
    	.HasKey(c => c.CarLicense);
}
//...

// Multiple Properties to the key ,復合主鍵的配置只能用Fluent API
modelBuilder.Entity<Car>()
  	.HasKey(c => new { c.CarLicense, c.CarFrameCode });

Generated Values

 中文應該是叫值的自動生成吧,我也不清楚。EF Core 上 有三種 Value Generation Pattern。分別是

  1. No Value Generation

    No value generation means that you will always supply a valid value to be saved to the database. This valid value must be assigned to new entities before they are added to the context.

    值不自動生成,每個屬性的值都需要指定,添加。這個我理解的意思應該是你保存到數據庫里面的值,每個必須是有效的,並且需要指定。

  2. Value Generated on Add

    Value generated on add means that a value is generated for new entities.

    Depending on the database provider being used, values may be generated client side by EF or in the database. If the value is generated by the database, then EF may assign a temporary value when you add the entity to the context. This temporary value will then be replaced by the database generated value during SaveChanges().

    If you add an entity to the context that has a value assigned to the property, then EF will attempt to insert that value rather than generating a new one. A property is considered to have a value assigned if it is not assigned the CLR default value (null for string, 0 for int, Guid.Empty for Guid, etc.).

    屬性的值在 添加到數據庫時自動添加。

  3. Value Generated on Add or Update

    Value generated on add or update means that a new value is generated every time the record is saved (insert or update).

    Like value generated on add, if you specify a value for the property on a newly added instance of an entity, that value will be inserted rather than a value being generated. It is also possible to set an explicit value when updating.

    屬性的值在 添加到數據庫或者更新時自動添加。

 當當看着上面這三個,我其實並不知道這三個到底是什么意思,接下來會用例子來演示一下這些具體意思,以及使用規范。

By convention, primary keys that are of an integer or GUID data type will be setup to have values generated on add. All other properties will be setup with no value generation.(當主鍵為 Interger 或者 GUID類型事,該主鍵的值會自動生成。)

 下面用實例來模擬一下:

我們新建一個實體 Blogs 如下:

//Entity Blog 
public class Blog
    {
        public int BlogId { get; set; }
        public string Url { get; set; }
    }
// Program.cs 
using (var db = new BookDbContext())
            {
                if (!db.Blogs.Any())
                {
                    var blog = new Blog
                    {
                        Url = "Https://q.cnblogs.com"
                    };
                    db.Blogs.AddRange(blog);
                    db.SaveChanges();
                }
            }

直接用在Program 用using 來演示效果,由於我們之前說到的主鍵為 Integer 類型的會自動生成值,所以數據庫中的值大家可想而知,就是下面這個

下面是用Data Annotation(數據注解)來演示的,也可以用Fluent API:

No Value Generation

如果我們不想讓它自動生成的話呢,也有辦法。向下面這樣:

 public class Blog
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int BlogId { get; set; }
        public string Url { get; set; }
    }

我在 BlogId 上加上 DatabaseGeneratedOption.None 之后,我們再重新運行上面的程序,發現數據庫的值如下所示:

為什么是 0 的原因呢,其實上面已經解釋過了:就是下面這句話

A property is considered to have a value assigned if it is not assigned the CLR default value (null for string, 0 for int, Guid.Empty for Guid, etc.). CLR 的默認值。

Fluent API 版本

modelBuilder.Entity<Blog>()
    .Property(b => b.BlogId)
    .ValueGeneratedNever();

Value Generated on Add

 比如我們還想在 Blog 實體里面加一個 更新時間 UpdateTime 屬性

public class Blog
    {
        public int BlogId { get; set; }
        public string Url { get; set; }
  		[DataGenerated(DatabaseGeneratedOption.Identity)]
  		public DateTime UpdateTime { get; set;}
    }

當我們配置成上面這樣,然后直接 dotnet run 時,發現程序報錯了。

Unhandled Exception: Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> Microsoft.Data.Sqlite.SqliteException: SQLite Error 19: 'NOT NULL constraint failed: Blogs.UpdateTime'.

Setting Explicit Value 中在OnModelCreating 中配置,使其自動生成,但是本地我使用SQLite 時無法自動生成,報錯。具體使用如下

   modelBuilder.Entity<Blog>()
                .Property(p => p.UpdateTime)
                .HasDefaultValueSql("CONVERT(date, GETDATE())");

Fluent API 版本

modelBuilder.Entity<Blog>()
    .Property(b => b.UpdateTime)
    .ValueGeneratedOnAdd();

Value generated on add or update (Data Annotations)

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime LastUpdated { get; set; }
}

Fulent API 版本

modelBuilder.Entity<Blog>()
    .Property(b => b.LastUpdated)
    .ValueGeneratedOnAddOrUpdate();

下面記錄一下 dotnet ef 命令的使用

dotnet ef migrations add name

dotnet ef database update 

dotnet ef migrations remove 

dotnet ef database drop


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM