新しいプロジェクトのデータアクセスレイヤーを作成しようとしているときに、OOP/Design/Genericsの問題(EF 4.3を使用してデータベースにアクセスする)としてしか想像できないものに遭遇しました。サービスレイヤでEntity Frameworkを参照する必要性を避けるにはどうすればよいですか?
は、主に私は、このデータ層との二つのことを達成したい:私は私のプロジェクトに持って
- 異なるコンテキストのオブジェクトは、同じ接続文字列を共有する必要があります。
- 一般的な実装を持つリポジトリクラス。
何らかの理由で、サービスレイヤーでEntityFrameworkを参照せずにソリューションをコンパイルできません。私が探しているのはこれを解決する方法です。ここに私が持っているもの:
//Project/Namespace BusinessLogicLayer.DomainClasses
//POCO classes mapped on Entity Framework.
//Project/Namespace DataAccessLayer.Base
//Base classes and interfaces for all data access layer, such as:
public abstract class BaseContext<TContext> : DbContext where TContext : DbContext
{
//To allow multiple contexts sharing the same connection string
protected BaseContext(): base("name=MyConnectionString") {}
}
//Generic interface for a read-only repository
public interface IReadOnlyRepository<T> : IDisposable where T : class
//Generic interface for a read/write repository
public interface IRepository<T> : IReadOnlyRepository<T> where T : class
//Basic implementation for a read-only repository
public abstract class BaseReadOnlyRepository<C, T> : IReadOnlyRepository<T>
where T : class
where C : BaseContext<C>, new()
{
}
//Basic implementation for a read/write repository
public abstract class BaseRepository<C, T> : IRepository<T>
where T : class
where C : BaseContext<C>, new()
{
}
//Project DataAccessLayer.AccountContext/ Namespace DataAccessLayer
//Context class:
public class AccountContext : BaseContext<AccountContext> {}
//With this, I can have simple repositories:
public class UserRepository : BaseRepository<AccountContext, User>
{ //All implementation comes from the base abstract class, unless I need to change it (override methods)
}
私はデータアクセスとアプリケーション(Windowsフォーム)の間にサービスレイヤーを持っています。私はジェネリックリポジトリを持っているので、ジェネリックサービスを持っていることは良い考えです。リポジトリの構造に非常に似て終わり、では:
//Project/Namespace BusinessLogicLayer.Services
//Service layer supposed to reference only the repository project and not Entity Framework.
//Generic interface for a read-only service working with a read-only repository
public interface IReadOnlyService<T> where T : class {}
//Generic interface for a read/write service working with a read/write repository
public interface IService<T> : IReadOnlyService<T> where T : class
//Base implementation for a read-only service
public abstract class BaseReadOnlyService<T, R> : IReadOnlyService<T>
where T : class
where R : IReadOnlyRepository<T>, new()
{
}
//Base implementation for a read/write service
public abstract class BaseService<T, R> : IService<T>
where T : class
where R : IRepository<T>, new()
{
}
//Concrete sample service
public class UserService : BaseService<User, UserRepository>
{ //As with the repository I can change the default behavior of implementation overriding methods
}
この設定では、コンパイルする唯一の方法は、サービス層のプロジェクトでEntity Frameworkのを参照することです。 Entity Frameworkをそこで参照する必要性を避けるにはどうすればよいですか?
この時点で、私はすべてを投げ捨てて、すべてを再構築したいと思いますが、私のニーズ(DbContext共有接続文字列、コードの複製を避けるための汎用リポジトリ) 。
ありがとうございました。ありがとう。
--edit - 私はこれを理解するためにはquestion--
を投稿ここで私がやったいくつかの余分な手順を含め3時間後、私は上記と同じコードとサンプルプロジェクトを作成し始めました元のプロジェクトの結果を可能な限り模倣するいくつかの実装を加えました。
ドメインクラスプロジェクト、基本データレイヤープロジェクト全体、そしてコンテキストプロジェクトを作成しました。コンテキストクラスがDbContextから直接派生していなくても、コンテキストプロジェクトでEntity Frameworkを参照する必要があることに気付きました。代わりに、DbContextから派生した抽象クラスから派生します。私のコンテキストにはDbSetsとDbContextに関連する他の実装があるので、これは問題ありません。
次はリポジトリプロジェクトです。他のすべての3つ(ドメイン、基本データレイヤー、コンテキスト)を参照する必要があります。私のリポジトリにはコードはありません。すべての機能は祖先にある。リポジトリプロジェクトをコンパイルしようとしましたが、VSはEntity Frameworkを参照する必要があります。私はそれが実際にライブラリを埋め込むことの問題なのだろうかと思います。これが確認されれば、それは驚きになるだろう。 Entity Frameworkライブラリは他のプロジェクトの出力に存在します。なぜ私はここでもそれを参照する必要がありますか? VSがこれを必要としているのは何ですか?
とにかく、テスト目的のために、私は参照を追加しました。結局のところ、私はデータ層の中にいます。私はそれで生きることができます。サービスレイヤーに移動します。わかりやすくするために、すべてのサービスクラスを同じプロジェクトに入れました。
考えられる1つの欠点は、サービス抽象クラスの制約の1つがリポジトリインターフェイスであることです。そのためには、私のサービス層のベースデータレイヤへの参照を追加する必要があります。おそらく既にここには私がリポジトリ参照のみを使うことを可能にする何かがあります。私はオプションがないが、基本データ層を参照する。
最後に、具体的なサービスが作成され、VSから次のエラーメッセージが表示されます。 'System.Data.Entity.DbContext'型は、参照されていないアセンブリで定義されています。アセンブリ 'EntityFramework、Version = 4.3.1.0、Culture = neutral、PublicKeyToken = b77a5c561934e089'への参照を追加する必要があります。
したがって、結局のところ、サービスレイヤーでEntity Frameworkを参照するしか方法はありません。そして、ある時点では、Windows Forms Appを構築するときに、Entity Frameworkも参照する必要があります。
これらの参照がないようにするにはどうすればよいですか?この構造にはどのような改善がありますか?
私の知る限りでは、私のアプリは確かにEntity Frameworkが他の層のどこにでも関わっていることを知る必要はありません。どちらもサービス層ではありません。サービスはリポジトリのみを消費します。リポジトリは、テスト用に偽のデータを提供することさえできます。
誰かが興味がある場合は、私がこれを書いている間に作成したプロジェクトをアップロードしました。これはバイナリを全く持たない1,17Mbのzipファイルです(ただし、Nugetを使って入手したEntity Framework 4.3.1のDLLを除く)。リンク:http://www.mediafire.com/?b45zkedy2j7eocc。
また、ありがとうございました。
愚かな質問のようですが、私は確かめる必要があると感じています。データアクセスレイヤーは現在サービスレイヤーでコンパイルされていますか? – tmesser
ハム...全く馬鹿ではない。実際、あなたは私を正しい方向に向けるかもしれないと思います。あなたのコメントを読んだ後、私は問題を示すサンプルプロジェクトを作成しました。私は上記の元の質問の後に結果を入れます。あなたの質問については、データアクセス層は異なるdllにコンパイルされません。 –