2015-08-19 5 views
1

У меня есть .Net-решение с несколькими проектами для следующих слоев.Присоединение нескольких таблиц при использовании общего репозитория в C#

  • Бизнес (папка решения)
    • ядро ​​(проект)
    • Интерфейсы (проект)
  • данных (папка решения)
    • данных (проект)
  • Presentation (папка раствора)
    • админпанели (проект)
  • Shared (папка раствора)
    • Common (проект)

Я реализовал общий репозиторий шаблон с уровнем IoC с использованием Unity, то есть Microsoft.Practices.Unity. Все работает отлично, за исключением случаев, когда я хочу сделать несколько таблиц простых или сложных объединений. Я пробовал много разных способов. Я прошел через каждый существующий поток здесь, на SO относительно объединений в репозитории, но ни один из них не помогает в том, что мне нужно.

Вот мой класс репозитория.

public class Repository<TEntity> : IRepository<TEntity> where TEntity : class, IEntity 
    { 
     protected BuyatimeshareModel Context { get; private set; } 

     public Repository(IContextFactory contextFactory) 
      : this(contextFactory.Get()) 
     { 
     } 

     protected Repository(BuyatimeshareModel context) 
     { 
      context.Database.Log = message => { Common.Logging.Log(message); }; 
      Context = context; 
     } 
     IDbSet<TEntity> DbSet 
     { 
      get 
      { 
       return Context.Set<TEntity>(); 
      } 
     } 
     public TEntity Add(TEntity instance) 
     { 
      DbSet.Add(instance); 
      Context.SaveChanges(); 
      return instance; 
     } 

     public void Remove(TEntity instance) 
     { 
      DbSet.Remove(instance); 
      Context.SaveChanges(); 
     } 
     public TEntity FindOne(Expression<Func<TEntity, bool>> predicate) 
     { 
      return DbSet.AsQueryable().FirstOrDefault(predicate); 
     } 

     public IEnumerable<TEntity> All() 
     { 
      return DbSet.AsQueryable(); 
     } 

     public IEnumerable<TEntity> Query() { IQueryable<TEntity> query = DbSet; return query.ToList(); } 

     public IEnumerable<TEntity> FindAll(Expression<Func<TEntity, bool>> predicate) 
     { 
      return DbSet.AsQueryable().Where(predicate); 
     } 

     public int Count() 
     { 
      return DbSet.AsQueryable().Count(); 
     } 

     public int Count(Expression<Func<TEntity, bool>> predicate) 
     { 
      return DbSet.AsQueryable().Count(predicate); 
     } 

     public bool Exists(Expression<Func<TEntity, bool>> predicate) 
     { 
      return DbSet.AsQueryable().Any(predicate); 
     } 
    } 

Вот мой слой IoC.

public class UnityControllerFactory : DefaultControllerFactory 
    { 
     IUnityContainer container; 

     public UnityControllerFactory(IUnityContainer container) 
     { 
      this.container = container; 
     } 

     protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) 
     { 
      try 
      { 
       if (controllerType == null) 
        throw new ArgumentNullException("controllerType"); 

       if (!typeof(IController).IsAssignableFrom(controllerType)) 
        throw new ArgumentException(string.Format(
         "Type requested is not a controller: {0}", controllerType.Name), 
         "controllerType"); 

       return container.Resolve(controllerType) as IController; 
      } 
      catch { return null; } 
     } 

     public static void Configure() 
     { 
      IUnityContainer container = new UnityContainer(); 
      /*string connectionString = ConfigurationManager.ConnectionStrings["Connection"].ConnectionString;*/ 
      container.RegisterType<IContextFactory, ContextFactory>(new ContainerControlledLifetimeManager())//, new InjectionConstructor(connectionString)) 
        .RegisterType<IUnitOfWork, UnitOfWork>(new ContainerControlledLifetimeManager()) 
        .RegisterType<IAdminService, AdminService>() 

        .RegisterType(typeof(IRepository<>), typeof(Repository<>)); 
      ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(container)); 
     } 
    } 

И, наконец, вот мой уровень услуг, где я пытаюсь запросить некоторые данные из хранилища слоя.

public class AdminService : IAdminService 
    { 
     private readonly IRepository<press_releases> pressReleasesRepo; 
     private readonly IRepository<tblads> adsRepo; 
     private readonly IRepository<tblresorts> resortsRepo; 

     public AdminService(IRepository<press_releases> _pressReleasesRepo, IRepository<tblads> _adsRepo, IRepository<tblresorts> _resortsRepo) 
     { 
      pressReleasesRepo = _pressReleasesRepo; 
      adsRepo = _adsRepo; 
      resortsRepo = _resortsRepo; 
     } 
     public List<press_releases> Test() 
     { 
      var data = pressReleasesRepo.FindAll(p => p.pr_id > 0); 
      var data1 = 
       (from a in adsRepo.Query() 
        join r in resortsRepo.Query() on a.resort_id equals r.resort_id 
        where a.ad_id == 413 
        select new 
        { 
         OwnerId = a.owner_id, 
         ResortName = r.name, 
         AdId = a.ad_id, 
         AskingPrice = a.askingPriceInt 
        }).ToList(); 

      var model = data.ToList(); 
      return model; 
     } 
    } 

Теперь здесь мы имеем два запроса. данные и data1

данных просто запрашивая одну единственную таблицу с критериями и его возвращающимся результаты, как и ожидалось. Здесь все хорошо.

Но, в data1, также технически возвращение именно конечный результат, что я хочу, но я также необработанный SQL регистратор в месте, чтобы увидеть, что происходит за кулисами, и то, что он делает это для запроса как объявления таблицы и таблицу курортов, используя , выберите * эквивалентный оператор, а затем, когда результаты возвращаются из обеих таблиц, он применяет соединения в памяти и возвращает результат после фильтрации через предложение where. Таким образом, в основном, его сканирование занимает около 100000 строк, хотя я и присоединяюсь, и где предложение находится на месте и в конце концов, оно возвращает одну строку с идентификатором объявления 413.

Одна вещь, чтобы записать то, что я звоню Query метод класса репозитория при выполнении объединения для data1 который возвращающая IEnumerable. Я не смог изменить его на IQueryable, потому что тогда возникло исключение из-за того, что какое-то сообщение, подобное запросу linq, ссылается на разные контексты.

Может ли кто-нибудь помочь мне изменить этот код, чтобы я мог применять реальные sql-соединения между репозиториями или если есть способ изменить этот код, добавив средний слой в качестве моста. Мне нужно что-то сделать дальше. Я искал везде, но безрезультатно. Я уверен, что я не первый в мире, у которого могла быть эта проблема. Там определенно были бы другие, имеющие аналогичную проблему, и может быть кто-то, кто нашел реальный путь.

Мои инструменты и технологии заключаются в следующем.

  • Visual Studio 2013
  • .Net Framework 4.0
  • MySQL Database
  • MySQL для Visual Studio 1.2.4
  • MySQL Connector 6.9.6
  • Entity Framework 6
  • для Windows 10 Pro x64

Пожалуйста, дайте мне знать, если есть что-то, что я мог пропустить.

Любая помощь была бы принята с благодарностью.

Edit:

Вот ContextFactory класс

public class ContextFactory : IContextFactory 
    { 
     private bool _isDisposed; 
     private SomeModel _context; 

     public ContextFactory() 
     { } 

     public SomeModel Get() 
     { 
      _context = new SomeModel(); 
      return _context; 
     } 

     ~ContextFactory() 
     { 
      Dispose(false); 
     } 

     public void Dispose() 
     { 
      Dispose(true); 
      GC.SuppressFinalize(this); 
     } 

     protected virtual void Dispose(bool disposing) 
     { 
      if (!_isDisposed && disposing && (_context != null)) 
       _context.Dispose(); 

      _isDisposed = true; 
     } 
    } 

ответ

0

Вот метод, который вы имеете в своем хранилище, которое вы используете в вашем data1.

public IEnumerable<TEntity> Query() { IQueryable<TEntity> query = DbSet; return query.ToList(); } 

Всякий раз, когда вы нажимаете «.ToList()», он попадает в базу данных.

Если вы хотите сначала создать запрос, а затем выполнить его, используйте свойство «DbSet» вашего репозитория.

+0

Большое спасибо за ваш ответ. Я уже упоминал об этом ранее в своем вопросе, что мне известно, что я возвращаю тип IEnumerable вместо IQueryable, то есть немедленный запрос и отложенный. Но это давало мне ошибку в разных контекстах. Из-за этого я не смог пропустить .ToList(). Надеюсь, это объяснит мою проблему. –

+1

Можете ли вы отправить код, связанный с ContextFactory. Вы получаете от него свой DBContext, создает ли он каждый раз этот контекст или кэшируется. –

+1

Добавьте поле GUID в свой ContextFactory и запишите, что на каждом Get, и посмотрите, совпадают ли они. См. Эту ссылку для получения дополнительных методов тестирования http://www.ladislavmrnka.com/2011/03/unity-build-in-lifetime-managers/ –