Entity Framework(EF) を ORM として使用して SQL Server とリンクする新しいプロジェクトを開始しようとしています。私は、抽象化に関して EF を操作し、最終的にコードをテスト可能にするための優れたアプローチを理解するために、大量の読書を行ってきました。
問題は、読めば読むほど混乱することです。
私が良い方法だと思ったのは:
私はリポジトリルートをたどり、インターフェースを介して簡単に注入できるようにし、テスト目的で簡単にモックできるようにします。私が見つけたように見える多くの例から、このアプローチを誓う人はたくさんいます。EF と対話するリポジトリ パーツについては、リポジトリにビジネス ロジックがないため、統合テストを行うつもりでした。それを処理するために、それをサービス/コントローラー クラスにシフトしました。
リポジトリ パターンは不当な抽象化であると言う人もいます
http://ayende.com/blog/3955/repository-is-the-new-singleton
他のリンクがありましたが、この質問にあまりにも多くのことを殺到させたくありませんでした
私はこれを理解しています.EFとその実装は本質的に抽象化であることを理解していますが、私には具体的なもののように思えます(アプリケーションの範囲外のものにヒットします.DB)私にとっての問題はそれは、おそらくサービス内からデータ コンテキストと作業単位とやり取りする (少なくとも初期アーキテクチャでは) テストの問題を押し上げますが、データ アクセス ログインとビジネス ロジックを混在させているように感じます。レベル、そして一体どうやってそれをユニットテストするのですか?
私はあまりにも多くのことを読んだようで、今では明確な方向性がなく、避けられないコーダー ブロックが設定されています。クリーンでテストできるアプローチを探しています。
更新 - 私が始めようとしている解決策
サイモンからの回答とは少し異なる道をたどりましたが、読んだ記事のおかげで、彼は再び提出したので、もう一度やり直しました。まず、既存のデータベースがあり、何らかの理由でデザイナー ツールが気に入らないため、Code First を使用しています。いくつかの単純な POCO オブジェクトといくつかのマッピングを作成しました。ここでは簡単にするために、1 つの POCO/マッピングとそうでないものだけを示します。
ポコ
public abstract class BaseEntity<T>
{
[Key]
public T Id { get; set; }
public string Name { get; set; }
public DateTime CreatedOn { get; set; }
}
public class Project : BaseEntity<int>
{
public virtual ICollection<Site> Sites { get; set; }
public bool Active { get; set; }
}
作業単位インターフェース
public interface IUnitOfWork
{
IDbSet<Project> Projects { get; }
void Commit();
}
環境
internal class MyContext : DbContext
{
public MyContext(string connectionString)
: base(connectionString)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ProjectMap());
}
}
具体的な作業単位
public class UnitOfWork : IUnitOfWork
{
readonly MyContext _context;
const string ConnectionStringName = "DBConn";
public UnitOfWork()
{
var connectionString = ConfigurationManager.ConnectionStrings[ConnectionStringName].ConnectionString;
_context = new FosilContext(connectionString);
}
public IDbSet<Project> Projects
{
get { return _context.Set<Project>(); }
}
public void Commit()
{
_context.SaveChanges();
}
}
基本的なテスト コード
var _repo = new UnitOfWork().Projects;
var projects = from p in _repo
select p;
foreach (var project in projects)
{
Console.WriteLine(string.Format("{0} - {1} - {2} - {3})", project.Id, project.Name, project.Active.ToString(), project.CreatedOn.ToShortDateString()));
}
Console.Read();
UnitOfWork は自明ですが、具体的なコンテキストに基づいて、偽の IUnitOfWork を作成し、テストのために偽の IDBSet に渡すことができます。私にとって、これはアーキテクチャ的に私を噛むために戻ってくるかもしれませんが、この抽象化された EF の上にレポがありません (私は思います)。記事で説明されているように、IDbSet は Repo と同等であるため、私はそれを使用しています。カスタム コンテキストを UoW の背後に隠していますが、それがどのように機能するかを見ていきます。
私が今考えているのは、これをサービスレイヤーで使用できるということです。これは、データとビジネスルールの取得をカプセル化しますが、EF 固有のアイテムを偽造できるため、ユニットテストが可能である必要があります。うまくいけば、それでコントローラーがかなりスリムになりますが、わかります:)