EF Core (Entiti Framework Core)

公式ドキュメント

参考メモ

インストール

1
2
3
4
5
6
7
8
dotnet add package Microsoft.EntityFrameworkCore --version 6.0.15
dotnet add package Microsoft.EntityFrameworkCore.InMemory

dotnet new tool-manifest
dotnet tool install dotnet-ef --version 6.0.15

dotnet tool uninstall --global dotnet-ef
dotnet tool install --global dotnet-ef --version 6.0.15

C#の型とデータベースの型を合わせる

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace SportsStore.Models;

public class Product
{
    public long? ProductId { get; set; }

    [Required(ErrorMessage = "Please enter a product name")]
    public string Name { get; set; } = string.Empty;

    [Required(ErrorMessage = "Please enter a description")]
    public string Description { get; set; } = string.Empty;

    [Required]
    [Range(0.01, double.MaxValue,
        ErrorMessage = "Please enter a positive price")]
    [Column(TypeName = "decimal(8, 2)")]
    public decimal Price { get; set; }

    [Required(ErrorMessage = "Please specify a category")]
    public string Category { get; set; } = string.Empty;
}

大文字小文字の無視: SQLiteだけ?

1
2
3
4
5
6
7
8
public async Task<City> GetByNameAsync(string name)
{
    name = name.Replace("-"," ");
    return await _context.Cities
        .Include(c => c.Country)
        .Include(c => c.Properties.Where(p => p.AvailableFrom < DateTime.Now))
        .SingleOrDefaultAsync(c => EF.Functions.Collate(c.Name, "NOCASE") == name);
}

シードでidGuidで発行する

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public void Configure(EntityTypeBuilder<Student> builder)
{
    builder.ToTable("Student");
    builder.Property(s => s.Age)
        .IsRequired(false);
    builder.Property(s => s.IsRegularStudent)
        .HasDefaultValue(true);

    builder.HasData
    (
        new Student
        {
            Id = Guid.NewGuid(),
            Name = "John Doe",
            Age = 30
        },
        new Student
        {
            Id = Guid.NewGuid(),
            Name = "Jane Doe",
            Age = 25
        },
        new Student
        {
            Id = Guid.NewGuid(),
            Name = "Mike Miles",
            Age = 28
        }
    );
}

シードを使う

SportsStoreの場合

1
2
using SportsStore.Models;
SeedData.EnsurePopulated(app);

シード: IdentityUser

シード: 多対多

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
    public class Book
    {
        public int BookId { get; set; }
        public string Title { get; set; }
        public Author Author { get; set; }
        public ICollection<BookCategory> BookCategories { get; set; }
    }
    public class Category
    {
        public int CategoryId { get; set; }
        public string CategoryName { get; set; }
        public ICollection<BookCategory> BookCategories { get; set; }
    }
    public class BookCategory
    {
        public int BookId { get; set; }
        public Book Book { get; set; }
        public int CategoryId { get; set; }
        public Category Category { get; set; }
    }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<BookCategory>()
            .HasKey(bc => new { bc.BookId, bc.CategoryId });
        modelBuilder.Entity<BookCategory>()
            .HasOne(bc => bc.Book)
            .WithMany(b => b.BookCategories)
            .HasForeignKey(bc => bc.BookId);
        modelBuilder.Entity<BookCategory>()
            .HasOne(bc => bc.Category)
            .WithMany(c => c.BookCategories)
            .HasForeignKey(bc => bc.CategoryId);
    }

データベースのリセット

1
dotnet ef database drop --force --context <データベースコンテキスト>

認証

認証用ユーザーにリレーションを張る

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using Microsoft.AspNetCore.Identity;

namespace <ProjectName>.Models;

public class ApplicationUser : IdentityUser
{
    public string FirstName { get; set; } = string.Empty;

    public string LastName { get; set; } = string.Empty;

    public DateTime BirthDate { get; set; }

    public virtual IEnumerable<Article>? Articles { get; set; }
}


namespace <ProjectName>.Models;

public class Article
{
    public int ArticleId { get; set; }

    public string Title { get; set; } = string.Empty;

    public string Description { get; set; } = string.Empty;

    public string? UserId { get; set; }

    public virtual ApplicationUser? User { get; set; }
}

認証用ユーザーの主キーを変える

マイグレーションの作成

1
2
dotnet dotnet-ef migrations add InitialCreate
dotnet dotnet-ef migrations add Rating
1
dotnet dotnet-ef migrations add InitialCreate -c <データベースコンテキスト>
1
dotnet ef migrations add InitialCreate

マイグレーションの反映

1
dotnet dotnet-ef database update

マイグレーションのundo

1
dotnet ef migrations remove

リバースエンジニアリング・データベースファースト・スキャフォールド

1
2
3
4
5
dotnet dotnet-ef dbcontext schema <接続文字列> <Provider>


dotnet dotnet-ef dbcontext scaffold "Data Source=RazorPages.Data.db" Microsoft.EntityFrameworkCore.Sqlite
dotnet dotnet-ef dbcontext scaffold 'Host=localhost;Database=mydb;Username=user;Password=pass' Npgsql.EntityFrameworkCore.PostgreSQL --output-dir Models --context-dir Context --context MyDbContext

リレーションの設定