2

私は次のようなベースリポジトリを持っています:

public class BaseRepository<T> : IBaseRepository<T> where T : class
{
    private DbContext _context;
    private IDbSet<T> _dbSet;

    protected DbContext Context
    {
        get
        {
            if (_context == null)
            {
                EFUnitOfWork currentUnitOfWork = (EFUnitOfWork)UnitOfWork.Current;
                _context = currentUnitOfWork.Context;
            }

            return _context;
        }
    }

    protected IDbSet<T> DbSet
    {
        get
        {
            if (_dbSet == null)
            {
                _dbSet = Context.Set<T>();
            }

            return _dbSet;
        }
    }

    public void Add(T entity)
    {
        DbSet.Add(entity);
    }

    public void Attach(T entity)
    {
        DbSet.Attach(entity);
    }

    public void Delete(T entity)
    {
        DbSet.Remove(entity);
    }

    public void Update(T entity)
    {
        Context.Entry(entity).State = System.Data.EntityState.Modified;
    }             

    public IQueryable<T> Get(string[] includes=null)
    {
        IQueryable<T> set = DbSet;
        if (includes != null)
        {
            foreach (string include in includes)
            {
                set = set.Include(include);
            }
        }
        return set;
    }
  1. User user = _usersRepository.Get().SingleOrDefault(u => u.Username == "gigi"); これにより、Rolesプロパティのないユーザーが返されます。これは問題ありません。

  2. User user = _usersRepository.Get(new string[] { "Roles" }).SingleOrDefault(u => u.Username == "gigi");これにより、ユーザーとRolesプロパティが返されます。これは問題ありません。

  3. List<User> users = _usersRepository.Get().Where(u => u.Username.StartsWith("gi")).ToList();

  4. List<User> users = _usersRepository.Get(new string[] { "Roles" }).Where(u => u.Username.StartsWith("gi")).ToList();

クエリ3と4はどちらも、Rolesプロパティを持つユーザーのリストを返します。クエリ3がロールを返すのはなぜですか?

LE:これは呼び出しです。コンテキストが破棄された後、ユーザーコレクションを調べます。

            List<User> users = _usersRepository.Get().Where(u => u.Username.StartsWith("gi")).ToList();
            UnitOfWork.Current.Dispose();

LE2:私は同じことを別々に行いました:

  1.         List<User> users;
            using (MyEntities ctx = new MyEntities ())
            {
                users= ctx.Users.ToList();
            }
    
  2.             List<User> users;
                using (MyEntities ctx = new MyEntities ())
                {
                    users= ctx.Users.Include("Roles").ToList();
                }
    

最初のケースではロールがロードされていませんが、2番目のケースでは問題ありません。

リポジトリのサンプルで何が間違っているのかわかりません。

LE3:これは作業単位です

    public class UnitOfWork
    {
        private const string HTTPCONTEXTKEY = "Repository.Key";

        private static IUnitOfWorkFactory _unitOfWorkFactory;
        private static readonly Hashtable _threads = new Hashtable();

        public static IUnitOfWork Current
        {
            get
            {
                IUnitOfWork unitOfWork = GetUnitOfWork();

                if (unitOfWork == null)
                {
                    _unitOfWorkFactory = ObjectFactory.GetInstance<IUnitOfWorkFactory>();
                    unitOfWork = _unitOfWorkFactory.Create();
                    SaveUnitOfWork(unitOfWork);
                }

                return unitOfWork;
            }
        }

        private static IUnitOfWork GetUnitOfWork()
        {
            if (HttpContext.Current != null)
            {
                if (HttpContext.Current.Items.Contains(HTTPCONTEXTKEY))
                {
                    return (IUnitOfWork)HttpContext.Current.Items[HTTPCONTEXTKEY];
                }

                return null;
            }
            else
            {
                Thread thread = Thread.CurrentThread;
                if (string.IsNullOrEmpty(thread.Name))
                {
                    thread.Name = Guid.NewGuid().ToString();
                    return null;
                }
                else
                {
                    lock (_threads.SyncRoot)
                    {
                        return (IUnitOfWork)_threads[Thread.CurrentThread.Name];
                    }
                }
            }
        }

        private static void SaveUnitOfWork(IUnitOfWork unitOfWork)
        {
            if (HttpContext.Current != null)
            {
                HttpContext.Current.Items[HTTPCONTEXTKEY] = unitOfWork;
            }
            else
            {
                lock (_threads.SyncRoot)
                {
                    _threads[Thread.CurrentThread.Name] = unitOfWork;
                }
            }
        }
    }
4

2 に答える 2

2

EFは、できるだけ多くのプロパティを設定しようとします。

データベース行をDbContextにロードした場合、EFはDbContextの存続期間中その行のデータを記憶します。

次に、その行を参照するエンティティをロードすると、EFはそのプロパティにInclude句の有無にかかわらずデータを入力します。

あなたの場合、クエリ2でRolesテーブル(の一部)をロードしています。
クエリ3を実行すると、これらの行はすでにDbContextにあるため、インクルードなしで入力されます。

于 2012-09-23T21:15:59.053 に答える
1

この行は、疑わしいことにシングルトンのように見えます。

EFUnitOfWork currentUnitOfWork = (EFUnitOfWork)UnitOfWork.Current;

そうであり、静的メンバーを使用してインスタンスを維持する従来のシングルトンパターンを使用している場合は、ダイナマイトで遊んでいます。データコンテキストを静的にしないでください。

理由はたくさんあります。1つ目は、これはコンテキストが破壊されることはなく、メモリを使い果たすまで(またはワーカープロセスが再起動するまで)変更追跡のためにメモリを消費し続けることを意味します。

2番目の最大の理由は、静的がプロセスのすべてのスレッド間で共有されることです。つまり、複数のユーザーが同じコンテキストを使用し、互いに踏みつけて、あらゆる種類の一貫性を破壊する可能性が非常に高くなります。

EFデータコンテキストはスレッドセーフではなく、同時実行性も安全ではありません(2つの異なるものです)。

この行:

UnitOfWork.Current.Dispose();

また、非常に悪いです。非常に注意しない限り、disposeをそのように呼び出すべきではありません。繰り返しますが、コンテキストが静的である場合は、別のスレッドがそれを使用している間にそれを破棄している可能性があります。

全体として、実際の問題は、データがキャッシュにプリロードされていることに関連していますが、そうでない場合もあります。UnitOfWorkの使用方法を真剣に再検討することをお勧めします。理想的には、依存性注入コンテナを使用してコンテキストの存続期間を管理するため、必要なときに、より一貫性のあるコンテキスト状態を維持できます。

于 2012-09-23T21:15:51.003 に答える