2

Data私は、主に、、、Servicesで区切られたmvc4Webアプリケーションを使用したEntityFrameworkコードファーストアプローチを使用して、階層化されたアプリケーションを構築していますWeb

私のウェブから私はこれを行います:

public void Foo() {
    EntityService _svc = new EntityService();
    Entity = _svc.FindById(1);
}

サービスメソッドは次のようになります。

private readonly MyContext _ctx = new MyContext();

public Entity FindById(long id) {
    return _ctx.Entities.SingleOrDefault(q => q.EntityId == id);
}

問題は、各サービスが独自のコンテキストを作成するため、複数のサービスを使用する必要がある場合です。

これを解決しようとして、私は次のようなことをしました:

public class MyContext : DbContext {
    private static MyContext _ctx;

    public MyContext() : base("name=myConnectionString") { }

    public static MyContext GetSharedInstance() {
        return GetSharedInstance(false);
    }

    public static MyContext GetSharedInstance(bool renew) {
        if(_ctx == null || renew)
            _ctx = new MyContext();

        return _ctx;
    }
}

私のサービスを次のように変更しました:

public class EntityService
{
    private readonly MyContext _ctx;

    public bool SharedContext { get; private set; }

    public EntityService()
        : this(false) { }

    public EntityService(bool sharedContext)
        : this(sharedContext, false) { }

    public EntityService(bool sharedContext, bool renew)
    {
        SharedContext = sharedContext;

        if (SharedContext)
            _ctx = MyContext.GetInstance(renew);
        else
            _ctx = new MyContext();
    }
}

ここで、コンテキストのインスタンスを共有したい場合は、次のようにします。

EntityService _entitySvc = new EntityService(true, true);
AnotherEntityService _anotherEntitySvc = new AnotherEntityService(true);

これは、少なくとも、これを克服するための適切な方法ですか?私は提供された助けに感謝します。ありがとう。

4

2 に答える 2

11

これまでにこれまでにこれまでにこれまでにこれまでにこれまでにこれまでに...これまでに...私はこれまでに言及しましたか?私は真剣です。静的データコンテキストを作成しないでください。決して。本当に。これをもう強調できますか?一度もない。それについても考えないでください。それについて考えることはあなたに脳腫瘍を与えるでしょう。

これは、依存性注入が本当に輝いている状況の1つです。依存性注入を使用すると、データコンテキストの有効期間を管理し、静的な場合のようにアプリプールの有効期間ではなく、リクエストの有効期間中データコンテキストを有効にすることができます。

共有コンテキストが悪い理由を詳しく説明します。コンテキストはクラス間だけでなく、スレッドやリクエスト間でも共有されます。つまり、サイトを同時に使用している2人のユーザーが、お互いのデータコンテキストを踏みにじり、あらゆる種類の問題を引き起こします。データコンテキストはスレッドセーフではなく、同時安全でもありません。

データコンテキストを複数のオブジェクトと共有する場合は、メソッド呼び出しの一部として、またはコンストラクター引数として、データコンテキストをそれらのオブジェクトに渡す必要があります。

ただし、依存性注入を介してこれを行うことを強くお勧めします。

于 2012-09-14T17:48:39.507 に答える
2

私はこれに他の何かを探していることに気づき、最近EntityFrameworkのリポジトリパターンを構築しました。フレームワークをカプセル化するように設計されており、独自のリポジトリパターンを際立たせています。あなたはミステリーマンのアドバイスに従いたいと思うでしょう。これが私があなたがそれに近づくことを提案する方法の大まかなサンプルです。

public class MyContext: DbContext, IUnitOfWork
{
    public IDbSet<Note> Notes { get; set; }
    public IDbSet<DomainType> DomainTypes { get; set; }
    public IDbSet<DomainValue> DomainValues { get; set; }
    public IDbSet<Party> Parties { get; set; }

    public MyContext() :base()
    {
        Configuration.LazyLoadingEnabled = false;
        Configuration.ProxyCreationEnabled = false;
    }
}

ご覧のとおり、DbContextはIUnitOfWorkであり、単にSaveChangesメソッドが含まれています。これは、リポジトリに渡すものです。

public abstract class BaseEfRepository<T, TU> : IRepository<T>
    where T : class 
    where TU : IUnitOfWork
{
    ...
    virtual public T GetSingle(Expression<Func<T, bool>> whereCondition)
    {
        Log.DebugFormat("Called GetSingle<{0}>()...", typeof(T));
        return MyEntitySet.Where(whereCondition).FirstOrDefault();
    } [etc...]

}

これには、基本的なリポジトリスタイルのコレクションアクセサーのほとんどと、カプセル化したいものがすべて含まれます。UnitOfWorkはリポジトリに渡されるため、同じトランザクションで必要な数のリポジトリを持つことができます。

public class NoteRepository: BaseEfRepository<Note, MyContext>
{
    public NoteRepository(MyContext uow) : base(uow)
    {
        MyEntitySet = uow.Notes;
    }
    public Note GetSingleWithParties(Expression<Func<Note, bool>> whereCondition)
    {
        return [... whatever ...]
    }

}

これがお役に立てば幸いです。

于 2013-03-28T19:00:30.143 に答える