C#のConsoleでEntityFramework「fluent APIで1対多のリレーションシップ」

C# コンピュータ
C#

EntityFrameworkで1対多のリレーションシップを定義してみます。

ソースコード

using Microsoft.EntityFrameworkCore;
using System.Dynamic;
using System.IO.Compression;

// グループエンティティクラス
public class Group
{
    public int GroupID { get; set; } = 0;
    public string GroupName { get; set; } = "";
    // 1対多のリレーションシップ
    public ICollection<User> Users { get; set; } = [];
}
// ユーザーエンティティクラス
public class User
{
    public int UserID { get; set; } = 0;
    public string Name { get; set; } = "";

    // 外部キー
    public int GroupID { get; set; } = 0;
    // グループのプロパティ
    public Group? Group { get; set; }
}

public class MyDbContext : DbContext
{
    public DbSet<Group> Groups => Set<Group>();
    public DbSet<User> Users => Set<User>();

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        // SQLiteデータベースファイルのパスを指定
        // アプリケーションの実行ディレクトリに MyDatabase.db が作成されます
        optionsBuilder.UseSqlite("Data Source=MyDatabase.db");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Fluent API を使って1対多のリレーションシップを定義
        modelBuilder.Entity<User>()
            .HasOne(e => e.Group) // User は1つの Group を持つ
            .WithMany(d => d.Users) // Group は複数の User を持つ
            .HasForeignKey(e => e.GroupID) // User の GroupId が外部キー
            .OnDelete(DeleteBehavior.Restrict); // Group が削除されても User は削除されないようにする
        
        // 初期データの追加
        modelBuilder.Entity<Group>().HasData(
            new Group { GroupID = 1, GroupName = "Expert" },
            new Group { GroupID = 2, GroupName = "Novice" }
        );

        modelBuilder.Entity<User>().HasData(
            new User { UserID = 1, Name = "taro", GroupID = 1 },
            new User { UserID = 2, Name = "hanako", GroupID = 2 },
            new User { UserID = 3, Name = "jiro", GroupID = 2 }
        );


    }
}

class Program
{
    static void Main()
    {
        System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);

        var context = new MyDbContext();

        // テーブル作成
        context.Database.EnsureCreated();

        var users = context.Users.Include(d => d.Group).ToList();

        foreach (var user in users)
        {
            if (user.Group is null)
            {
                Console.WriteLine($"{user.UserID} {user.Name} {user.GroupID}");
            }
            else
            {
                Console.WriteLine($"{user.UserID} {user.Name} {user.GroupID} {user.Group.GroupName}");
            }
        }
        // 結果
        // 1 taro 1 Expert
        // 2 hanako 2 Novice
        // 3 jiro 2 Novice
    }
}

感想

Groupには複数のUserが所属し、Userは一つGroupに所属するという関係を表現しています。
Group.UsersがICollectionだったり、User.Groupがnull許容だったりと、データベースのテーブルの項目をC#のプロパティとしてアクセスするための間口が用意されています。
テーブル同士の関係性(リレーションシップ)はOnConfiguring()内でfluent APIにより行われています。詳しくはコメントに記述していますので割愛しますが、上手にSQLは隠蔽されていますが、SQLを知らない人間が見ると(筆者を含む)チンプンカンプンなのでは無いかと思います。

ただ、内容は理解していない場合でも、使い方さえ知っていれば役立てることが出来るので、頑張って学習しようと思います。

コメント