mcpField
E
entity-framework-core

entity-framework-core

github.com/claude-dev-suite開発4665 回インストール4 日前に更新
リポジトリ

entity-framework-core について

.NET 開発者向けの Entity Framework Core クイックリファレンススキルです。DbContext、エンティティ設定、マイグレーション、LINQ クエリに加え、クエリ性能の指針と問題の調査方法を扱います。

主な機能

  1. 01DbContext の設定
  2. 02Fluent API によるエンティティ設定
  3. 03データベースのマイグレーションコマンド
  4. 04LINQ クエリと射影
  5. 05読み取り専用処理と一括操作の最適化
  6. 06よくある問題のトラブルシューティング

活用シーン

  1. 01データベースコンテキストとエンティティの設定
  2. 02マイグレーションによるデータベース更新
  3. 03読み取り専用クエリと一括操作の調整

MCP 対応

`mcp__documentation__fetch_docs` で Entity Framework Core の詳細ドキュメントを取得できると記載されています。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill entity-framework-core

インストール後、Claude Code で/entity-framework-coreを入力して読み込まれたか確認します。

詳細

Entity Framework Core - クイックリファレンス

詳細な知識:テクノロジーに entity-framework-core を指定して、mcp__documentation__fetch_docs を使用すると、包括的なドキュメントを参照できます。

DbContext のセットアップ

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

    public DbSet<User> Users => Set<User>();
    public DbSet<Order> Orders => Set<Order>();

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);
    }
}

// Registration
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("Default")));

エンティティの構成(Fluent API)

public class UserConfiguration : IEntityTypeConfiguration<User>
{
    public void Configure(EntityTypeBuilder<User> builder)
    {
        builder.HasKey(u => u.Id);
        builder.Property(u => u.Name).IsRequired().HasMaxLength(100);
        builder.Property(u => u.Email).IsRequired().HasMaxLength(255);
        builder.HasIndex(u => u.Email).IsUnique();

        // Relationships
        builder.HasMany(u => u.Orders)
            .WithOne(o => o.User)
            .HasForeignKey(o => o.UserId)
            .OnDelete(DeleteBehavior.Cascade);

        // Value conversion
        builder.Property(u => u.Status)
            .HasConversion<string>();

        // Default values
        builder.Property(u => u.CreatedAt)
            .HasDefaultValueSql("GETUTCDATE()");
    }
}

マイグレーション

# Add migration
dotnet ef migrations add InitialCreate

# Update database
dotnet ef database update

# Remove last migration (not applied)
dotnet ef migrations remove

# Generate SQL script
dotnet ef migrations script

# Revert to specific migration
dotnet ef database update MigrationName

LINQ クエリ

// Basic queries
var user = await context.Users.FindAsync(id);
var users = await context.Users.Where(u => u.IsActive).ToListAsync();
var user = await context.Users.FirstOrDefaultAsync(u => u.Email == email);

// Projection
var dtos = await context.Users
    .Where(u => u.IsActive)
    .Select(u => new UserResponse(u.Id, u.Name, u.Email))
    .ToListAsync();

// Include related data
var usersWithOrders = await context.Users
    .Include(u => u.Orders)
    .ThenInclude(o => o.OrderItems)
    .ToListAsync();

// Pagination
var page = await context.Users
    .OrderBy(u => u.Name)
    .Skip((pageNumber - 1) * pageSize)
    .Take(pageSize)
    .ToListAsync();

// Aggregation
var count = await context.Users.CountAsync(u => u.IsActive);
var avgAge = await context.Users.AverageAsync(u => u.Age);

リポジトリパターン

public interface IRepository<T> where T : class
{
    Task<T?> GetByIdAsync(int id);
    Task<IEnumerable<T>> GetAllAsync();
    Task AddAsync(T entity);
    void Update(T entity);
    void Remove(T entity);
    Task<bool> ExistsAsync(Expression<Func<T, bool>> predicate);
    Task SaveChangesAsync();
}

public class Repository<T> : IRepository<T> where T : class
{
    protected readonly AppDbContext _context;
    protected readonly DbSet<T> _dbSet;

    public Repository(AppDbContext context)
    {
        _context = context;
        _dbSet = context.Set<T>();
    }

    public async Task<T?> GetByIdAsync(int id) => await _dbSet.FindAsync(id);
    public async Task<IEnumerable<T>> GetAllAsync() => await _dbSet.ToListAsync();
    public async Task AddAsync(T entity) => await _dbSet.AddAsync(entity);
    public void Update(T entity) => _dbSet.Update(entity);
    public void Remove(T entity) => _dbSet.Remove(entity);
    public async Task<bool> ExistsAsync(Expression<Func<T, bool>> predicate)
        => await _dbSet.AnyAsync(predicate);
    public async Task SaveChangesAsync() => await _context.SaveChangesAsync();
}

パフォーマンスのヒント

ヒント実装
読み取り専用の場合は AsNoTracking() を使用するcontext.Users.AsNoTracking().ToListAsync()
投影には Select を使用するエンティティ全体の読み込みを避ける
AsSplitQuery() を使用するInclude による直積の爆発を防ぐ
コンパイル済みクエリを使用する頻繁に実行する処理には EF.CompileAsyncQuery(...) を使用する
バッチ処理を行うExecuteUpdateAsync / ExecuteDeleteAsync(EF Core 7+)
// Bulk update (EF Core 7+)
await context.Users
    .Where(u => u.LastLoginAt < cutoff)
    .ExecuteUpdateAsync(u => u.SetProperty(x => x.IsActive, false));

// Bulk delete
await context.Users
    .Where(u => u.IsDeleted)
    .ExecuteDeleteAsync();

アンチパターン

アンチパターン問題点適切な方法
表示のためにエンティティ全体を読み込むメモリの浪費、処理の遅延Select による投影を使用する
N+1 クエリパフォーマンスを著しく低下させるInclude または投影を使用する
AsNoTracking を使用しない不要なオーバーヘッドが発生する読み取り専用クエリで使用する
エンティティごとに SaveChanges を呼び出すバッチ処理が遅くなるすべての変更後に一度だけ呼び出す
DbContext をシングルトンとして使用するスレッドセーフではないAddDbContext(Scoped)を使用する

簡単なトラブルシューティング

問題考えられる原因解決策
トラッキングの競合エンティティはすでにトラッキングされているAsNoTracking を使用するか、デタッチする
マイグレーションの失敗モデルが一致していない未適用の変更を確認し、再ビルドする
クエリが遅いインデックスがない構成に HasIndex を追加する
遅延読み込みの失敗構成されていないInclude(明示的な読み込み)を使用する
同時実行の競合データが古い[ConcurrencyCheck] または RowVersion を追加する

コメント