3

私はしばらくの間プロジェクトに取り組んできました。最初は、一握りの本やオンライン記事でたくさんのパターンについて読んだ後、プログラムのアーキテクチャの計画に多くの時間を費やしました。EF5.0>リポジトリ/作業単位>MVVM>WPFを組み合わせることにしました。

私の最初のテストでは、それが完全に機能するように見えたので、私は決めたパターンにコミットし、それを実装するのに1か月を費やしました。トラブルが発生しているのは、もうすぐ終わりです。

解決できない問題の1つは、複雑なクエリを作成できないように見えることです。何をしようとしても、エラーが発生します。

このプログラムは、Entity Framework 5.0を使用して、当社のMSSql2005サーバー上のデータベースに接続します。そこから、エンティティごとにリポジトリクラスが存在します。各リポジトリは、そのコンストラクタでコンテキストを受け取り、標準のインターフェイスを実装します。

interface IRepository<T> where T : class
{
    IEnumerable<T> GetAll();
    IEnumerable<T> Query(Expression<Func<T, bool>> filter);
    void Add(T entity);
    void Remove(T entity);
}

基本クラスは次のようになります。

public abstract class Repository<T> : IRepository<T> where T : class
{
    protected IObjectSet<T> _objectSet;

    public Repository(ObjectContext context)
    {
        _objectSet = context.CreateObjectSet<T>();
    }

    public IEnumerable<T> GetAll()
    {
        return _objectSet;
    }

    public List<T> ToList()
    {
        return _objectSet.ToList<T>();
    }

    public IEnumerable<T> Query(Expression<Func<T, bool>> filter)
    {
        return _objectSet.Where(filter);
    }

    public void Add(T entity)
    {
        _objectSet.AddObject(entity);
    }

    public void Remove(T entity)
    {
        _objectSet.DeleteObject(entity);
    }

    public void Update(T entity)
    {
        _objectSet.UpdateModel(entity);
    }

    public abstract void Upsert(T entity);


}

具体的なリポジトリは次のようになります。

public class UserAccountRepository : Repository<UserAccount>
{
    public UserAccountRepository(ObjectContext context)
        : base(context)
    {
    }

    public UserAccount GetById(int id)
    {
        return _objectSet.SingleOrDefault(user => user.ID == id);
    }

    public override void Upsert(UserAccount user)
    {
        if (user == null)
            throw new ArgumentNullException();
        if (user.ID == 0 || GetById(user.ID) == null)
            Add(user);
        else
            Update(user);
    }
}

次はUnitOfWorkクラスです。このクラスは、各リポジトリの遅延ロードされたインスタンスを保持し、UnitOfWorkの存続期間中存続する独自のObjectContextをインスタンス化します。このコンテキストは、コンストラクターのリポジトリーに渡されます。

UnitOfWorkクラスはインスタンス化され、変更はパブリックにアクセス可能なリポジトリを介して行われ、その後、UnitOfWorkクラスのパブリックメソッドを介して保存または破棄されます。

UnitOfWorkクラス:

(私はUserAccount、ComponentPermissions、Componentのみを含めました。UserAccountは、中間テーブルComponentPermissionsで維持されている、さまざまなレベルのアクセス許可を持つ複数のコンポーネントにアクセスできます)

public class UnitOfWork : IDisposable
{


    #region Fields

    private readonly ObjectContext _context;

    private ComponentPermissionsRepository _componentPermissions;
    private ComponentRepository _components;
    private UserAccountRepository _userAccounts;

    #endregion //Fields


    #region Constructor

    public UnitOfWork()
    {
        _context = (new DataAccess.Entities() as IObjectContextAdapter).ObjectContext;
    }

    #endregion //Constructor


    #region Public Interface

    public ComponentPermissionsRepository ComponentPermissions
    {
        get
        {
            if (_componentPermissions == null)
            {
                _componentPermissions = new ComponentPermissionsRepository(_context);
            }

            return _componentPermissions;
        }

    }

    public ComponentRepository Components
    {
        get
        {
            if (_components == null)
            {
                _components = new ComponentRepository(_context);
            }

            return _components;
        }

    }


    public UserAccountRepository UserAccounts
    {
        get
        {
            if (_userAccounts == null)
            {
                _userAccounts = new UserAccountRepository(_context);
            }

            return _userAccounts;
        }

    }

    public void Commit()
    {
        _context.SaveChanges();
    }

    public void Dispose()
    {
        _userAccount = null;
        _component = null;
        _componentPermissions = null;
        _context.Dispose();
    }

    #endregion //Public Interface


}

EFでのクエリに関する記事をたくさん読んだのですが、上記のアーキテクチャに適用した場合、読んだものは何も機能しないようです...そして、自分の足を撃ったようなひどい気持ちがありますが、私はどこがわからない。

単一のUserAccountを指定して、アクセス可能なコンポーネントと対応するComponentPermissionsのリストを取得したいと思います。この種のクエリを実行するにはどうすればよいですか?EFナビゲーションプロパティは、直接の隣人に対してのみ機能するようです...私は明らかな何かを見逃していますか?

編集

私は自分の問題をもっと具体的にすべきだと指摘されています。私が克服できない最初のハードルは、すべての例が次のように見えることです。

context.Component.Include( c => c.ComponentPermissions.Select(cps => cps.UserAccount)).ToList();

見た目は良さそうですが、コンテキストを公開していません。公開しても、Componentのようなエンティティタイプはありません。しかし、GetAll()をIQueryableに変更したので、次のことをまとめることができました。

List<Component> comps = uow.Components.GetAll().Include(c => c.UserPermissions.Select(cps => cps.UserAccount)).ToList();
ComponentPermissions compPer = comps[0].UserPermissions.Select(up => up).Where(up => up.UserAccount.UserName == userAccount).FirstOrDefault();

これにより、特定のuserAccountに関連する最初のComponentPermissionsオブジェクトが返されます...しかし、これは、たとえそれがある程度機能したとしても、非常に間違っているように見えます(つまり、すべてではなく、1つのComponentPermissionsオブジェクトしか取得しなかったためです。それら...しかし、私はそれを行う方法を理解することができませんでした)

それで、それを見て、誰かがそれをする正しい方法を説明できますか?

4

1 に答える 1

1

うーん、ちょっとアホっぽいなぁ…

私は UnitOfWork で ObjectContext を取得していました:

_context = (new DataAccess.Entities() as IObjectContextAdapter).ObjectContext;

DataAccess.Entities() (私のデータ用に EF によって作成されたカスタム コンテキスト) のインスタンスを操作する必要があったとき。

リポジトリを作り直す必要がありましたが、追加の利点は、具体的なクラスを削除して、汎用リポジトリを使用できるようになったことです。

DataAccess.Entities() を ObjectContext にキャストしていたため、これらすべての問題が発生していましたが、これには特定のエンティティ タイプが含まれていませんでした...そのため、リポジトリからクエリを実行しようとしていましたが、リポジトリには独自のデータのみがロードされていましたタイプ。

1 行のコード... 3 日間の頭痛の種。典型的。

于 2012-11-27T21:29:05.487 に答える