Repozytorium w innym repozytorium

0

Cześć Mam taki problem chodzi o to że mam taką metodę:

        public async Task<PagedResult<TenureList>> GetAllActiveAsync(int? page, Expression<Func<TenureList, bool>> predicate)
        {

            var tenures = db.Tenures.Include(x=>x.Company).Where(x => x.IsActive == true && x.Company.IsActive == true && x.IsPremium == false).Select(x=> new TenureList
            { 
                Id = x.Id,
                Name = x.Name,
                Address = x.Address,
                CreatedAt = x.ConvertTenureDate(),
                IsActive = x.IsActive,
                CategoryId = x.CategoryId,
                City = x.City,
                CompanyId = x.CompanyId,
                CompanyName = x.GetCompanyName(),
                IsPremium = x.SetPremium(),
                LogoUrl = x.GetCompanyLogoUrl(),
                Rate = x.Rate,
                WorkTimeTypes = x.WorkTimeTypes,
                IsApply = _workApplicationRepository.CheckIsApply(userId, x.Id) // Tutaj
            });

...
}

Chodzi o to czy mogę używać inne repo w innym repo ?

3

Mam wrażenie, że nie do końca rozumiesz, do czego służy repozytorium. :/ Podrzucę Ci chyba najczęściej linkowany artykuł na tym forum :P http://commitandrun.pl/2016/05/11/Repozytorium_najbardziej_niepotrzebny_wzorzec_projektowy/

A tak ogólnie, to tworzenie zależności między klasami z tej samej warstwy prowadzi do problemów.

0

Kurcze tak wygląda całe moje "repozytorium" które jest tak naprawdę DAO tak to przynajmniej rozumiem to czy tak naprawdę potrzebne bedzię mi repozytorium ?
a jeśli tak to jak mam je zaimplementować bo tego nie rozumiem :(

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Work.Aggregated.Tenure;
using Work.Core.Domain;
using Work.Data;
using Work.Repositories.Interfaces;
using Work.Web.Essentials.ServiceResponse;

namespace Work.Repositories
{
    public class TenureRepository : ITenureRepository
    {
        private readonly ApplicationDbContext db;
        private readonly IWorkApplicationRepository workApplicationRepository;

        public TenureRepository(ApplicationDbContext _db, IWorkApplicationRepository workApplicationRepository)
        {
            db = _db;
            this.workApplicationRepository = workApplicationRepository;
        }

        public async Task AddAsync(Tenure tenure)
        {
            await db.Tenures.AddAsync(tenure);
            db.SaveChanges();
        }

        public async Task ChangeStatusAsync(Tenure tenure)
        {
            var status = !tenure.IsActive;

            tenure.SetStatus(status);

            db.Entry(tenure).State = EntityState.Modified;
            await db.SaveChangesAsync();
        }

        public async Task DeleteAsync(Tenure tenure)
        {
            db.Entry(tenure).State = EntityState.Deleted;
            await db.SaveChangesAsync();
        }

        public async Task EditAsync(Tenure tenure)
        {
            db.Entry(tenure).State = EntityState.Modified;
            await db.SaveChangesAsync();
        }

        public async Task<PagedResult<TenureList>> GetAllActiveAsync(string userId, int? page, Expression<Func<TenureList, bool>> predicate)
        {

            var tenures = db.Tenures.Include(x=>x.Company).Where(x => x.IsActive == true && x.Company.IsActive == true && x.IsPremium == false).Select(x=> new TenureList
            { 
                Id = x.Id,
                Name = x.Name,
                Address = x.Address,
                CreatedAt = x.ConvertTenureDate(),
                IsActive = x.IsActive,
                CategoryId = x.CategoryId,
                City = x.City,
                CompanyId = x.CompanyId,
                CompanyName = x.GetCompanyName(),
                IsPremium = x.SetPremium(),
                LogoUrl = x.GetCompanyLogoUrl(),
                Rate = x.Rate,
                WorkTimeTypes = x.WorkTimeTypes,
                IsApply = workApplicationRepository.CheckIsApply(userId, x.Id)
            });
            


            tenures = tenures.Where(predicate);
            var tenuresCount = tenures.Count();

            page = page - 1;
            var pageSize = 10;
            int startPage = 1;
            int endPage = 5;
            int totalItems = tenures.Count();
            int totalElements = tenuresCount;
            int totalPages = (int)Math.Ceiling((decimal)totalItems / pageSize);
            int currentPage = page ?? 1;

            if (currentPage >= 5 && currentPage <= (totalPages - 4))
            {
                startPage = currentPage - 1;
                endPage = currentPage + 1;
            }
            else if (currentPage > (totalPages - 4))
            {
                startPage = totalPages - 4;
                endPage = totalPages;
            }

            if (startPage <= 0)
            {
                startPage = 1;
            }
            if (endPage >= totalPages)
            {
                endPage = totalPages;
            }

            var result = await tenures
                .OrderByDescending(x => x.CreatedAt)
                .Skip((int)currentPage * pageSize)
                .Take(pageSize)
                .ToListAsync();


            return new PagedResult<TenureList>
            {
                Results = result,
                PageSize = pageSize,
                TotalCount = totalPages,
                StartPage = startPage,
                EndPage = endPage,
                CurrentPage = currentPage,
                ResultCount = totalItems,
                TotalElements = totalElements
            };
        }

        public async Task<IReadOnlyList<TenureListAdmin>> GetAllAsync()
        {
            return await db.Tenures.Include(x => x.Company).Select(x => new TenureListAdmin
            {
                Id = x.Id,
                CreatedAt = x.CreatedAt.ToString("dd/MM/yyyy"),
                IsActive = x.IsActive,
                CategoryId = x.CategoryId,
                City = x.City,
                CompanyId = x.CompanyId,
                CompanyName = x.GetCompanyName(),
                Name = x.Name,
                Rate = x.Rate,
                ApplyCount = x.ApplyCount
            }).ToListAsync(); 
        }

        public async Task<IReadOnlyList<Tenure>> GetAllPremiumAsync()
        {
            return await db.Tenures.Where(x => x.IsActive == true && x.Company.IsActive == true && x.IsPremium == true).Include(x => x.Company).OrderByDescending(x => x.CreatedAt).ToListAsync();
        }

        public async Task<Tenure> GetAsync(long id)
        {
            return await db.Tenures.Include(x => x.Company).SingleOrDefaultAsync(x => x.Id == id);
        }

        public async Task<IEnumerable<DailyTenureAdd>> GetDailyTenureAdd()
        {
            var items = new List<DailyTenureAdd>();

            for (int i = -7; i <= 0; i++)
            {
                var date = DateTime.Now.AddDays(i).Date;
                var item = await db.Tenures.GroupBy(x => date).Select(x =>
                   new DailyTenureAdd
                   {
                       CountTenures = x.Where(z=>z.CreatedAt.Date.ToString("dd/MM/yyyy") == date.Date.ToString("dd/MM/yyyy")).Count(),
                       CreatedAt = x.Key.ToString("dd/MM/yyyy")
                   }).SingleOrDefaultAsync();

                items.Add(item);
            }



            return items;
        }

        public async Task<TenureDetails> GetDetailsAsync(long id)
        {
            return await db.Tenures.Include(x => x.Company).Select(x=> new TenureDetails { 
                Id = x.Id,
                Address = x.Address,
                AgreementTypes = x.ConvertAgreementTypes(),
                CreatedAt = x.ConvertTenureDate(),
                Description = x.Description,
                CategoryId = x.CategoryId,
                City = x.City,
                CompanyId = x.CompanyId,
                CompanyName = x.GetCompanyName(),
                ExpirationDate = x.ExpirationDate,
                IsActive = x.IsActive,
                IsPremium = x.SetPremium(),
                LogoUrl = x.GetCompanyLogoUrl(),
                Name = x.Name,
                Rate = x.Rate,
                WorkTimeTypes = x.ConvertWorkTimeTypes()
            
            }).SingleOrDefaultAsync(x => x.Id == id);
        }

        public async Task<IReadOnlyList<SimpleTenureList>> GetSimpleTenuresAsync(long id)
        {
            var tenure = await GetAsync(id);

            var payload = await db.Tenures.Include(x => x.Company).Where(x => x.Name.ToLower().Contains(tenure.Name.ToLower()) && x.IsActive == true && x.Id != id).Select(x => new SimpleTenureList
                {
                    Id = x.Id,
                    Name = x.Name,
                    City = x.City,
                    CompanyName = x.GetCompanyName(),
                    Rate = x.Rate
                }).ToListAsync();

            return payload;
        }

        public async Task<IReadOnlyList<TenureList>> GetTenureCompanyAsync(long id)
        {
            return await db.Tenures.Include(x => x.Company).Where(x => x.Company.Id == id && x.IsActive == true).Select(x => new TenureList
            {
                Id = x.Id,
                Name = x.Name,
                Address = x.Address,
                CreatedAt = x.ConvertTenureDate(),
                IsActive = x.IsActive,
                CategoryId = x.CategoryId,
                City = x.City,
                CompanyId = x.CompanyId,
                CompanyName = x.GetCompanyName(),
                IsPremium = x.SetPremium(),
                LogoUrl = x.GetCompanyLogoUrl(),
                Rate = x.Rate,
                WorkTimeTypes = x.WorkTimeTypes
            }).OrderByDescending(x=>x.CreatedAt).ToListAsync();
        }

        public async Task<int> GetTenureCountAsync()
        {
            return await db.Tenures.Where(x => x.IsActive == true && x.Company.IsActive == true).CountAsync();
        }

        public async Task IncrementApplyCount(long id)
        {
            var tenure = await db.Tenures.FirstOrDefaultAsync(x => x.Id == id);

            tenure.IncrementApplyCount();

            db.Entry(tenure).State = EntityState.Modified;
            await db.SaveChangesAsync();
        }
    }
}

1
var tenures = db.Tenures.Include(x=>x.Company).Where(x => x.IsActive == true && x.Company.IsActive == true && x.IsPremium == false).Select(x=> new TenureList
{ 
	Id = x.Id,
	Name = x.Name,
	Address = x.Address,
	CreatedAt = x.ConvertTenureDate(),
	IsActive = x.IsActive,
	CategoryId = x.CategoryId,
	City = x.City,
	CompanyId = x.CompanyId,
	CompanyName = x.GetCompanyName(),
	IsPremium = x.SetPremium(),
	LogoUrl = x.GetCompanyLogoUrl(),
	Rate = x.Rate,
	WorkTimeTypes = x.WorkTimeTypes,
	IsApply = _workApplicationRepository.CheckIsApply(userId, x.Id) // Tutaj
});

to się w ogóle wykonuje po stronie bazy? co zwraca to CheckIsApply?

0

bez property IsApply tak a z nią taki błąd:

A second operation started on this context before a previous operation completed
1

Pewnie _workApplicationRepository ma inną instancję contextu niż TenureRepository repository.

Trzeba się zastanowić czy odpowiedni lifetime jest ustawiony przy rejestrowaniu DI lub czy nie chcesz np. utworzyć instancji TenureRepository w ctorze _workApplicationRepository podając ten sam context do tego "repo".


  • Transient objects are always different; a new instance is provided to every controller and every service.

  • Scoped objects are the same within a request, but different across different requests.

  • Singleton objects are the same for every object and every request.

0
WeiXiao napisał(a):

Pewnie _workApplicationRepository ma inną instancję contextu niż TenureRepository repository.

Trzeba się zastanowić czy odpowiedni lifetime jest ustawiony przy rejestrowaniu DI lub czy nie chcesz np. utworzyć instancji TenureRepository w ctorze _workApplicationRepository podając ten sam context do tego "repo".


  • Transient objects are always different; a new instance is provided to every controller and every service.

  • Scoped objects are the same within a request, but different across different requests.

  • Singleton objects are the same for every object and every request.

Pomogło dodanie dodanie

ServiceLifetime.Transient
            services.AddDbContext<ApplicationDbContext>(options => { 
                options.UseSqlServer(conntectionString); 
            }, ServiceLifetime.Transient);

@WeiXiao a co sądzisz o tym repo ? :)

1

przy transient działa? O.O

2

W taki sposób jak to napisałeś będzie to działać bardzo wolno ponieważ każdy select z tego zapytania dodatkowo wykonuje koleje zapytanie.
Np. przy 10 aktywnych (Tenures) będziesz miał dodatkowo 10 innych zapytań żeby sprawdzić pole IsApply - czyli łącznie leci 11 zapytań do bazy.

Dużo wydajniej będzie użyć jednego contextu chyba, że nie masz takiej możliwości.

2

A czemu repozytorium korzysta z innego repozytorium? Klasy z tej samej warstwy abstrakcji nie powinny korzystać z siebie wzajemnie, w ten sposób powstaje spaghetti.

A tak przy okazji, to po co konwertować DateTime na string w celu ich porównywania?

1

A czemu repozytorium korzysta z innego repozytorium? Klasy z tej samej warstwy abstrakcji nie powinny korzystać z siebie wzajemnie, w ten sposób powstaje spaghetti.

Dlaczego? Pierwszy raz słyszę o takiej zasadzie. Nie mówi że jest zła czy dobra po prostu jestem ciekawy.

0

Nie. Nie mozesz. Jeśli już masz opanowany DbContext w repo (wiem, wiem) to dlaczego go nie użyjesz? Drugie repo pewnie ma własny DbContext.
Tenures nie ma nawigacji do tego co zwraca applicationRepository? Nie możesz wyciągnąć IsApply z x. ...?

0

Przeprojektowałem trochę baze i działa mi tak:

        public async Task<PagedResult<TenureList>> GetAllActiveAsync(int? page, Expression<Func<TenureList, bool>> predicate, string userId = null)
        {

            var tenures = db.Tenures.Include(x=>x.Company).Include(x=>x.WorkApplications).Where(x => x.IsActive == true && x.Company.IsActive == true && x.IsPremium == false).Select(x=> new TenureList
            { 
                Id = x.Id,
                Name = x.Name,
                Address = x.Address,
                CreatedAt = x.ConvertTenureDate(),
                IsActive = x.IsActive,
                CategoryId = x.CategoryId,
                City = x.City,
                CompanyId = x.CompanyId,
                CompanyName = x.GetCompanyName(),
                IsPremium = x.SetPremium(),
                LogoUrl = x.GetCompanyLogoUrl(),
                Rate = x.Rate,
                WorkTimeTypes = x.WorkTimeTypes,
                IsApply = userId != null ? x.WorkApplications.Any(s=>s.ApplicationUserId == userId && s.TenureId == s.Id) : false
            });

Lepsze rozwiązanie ?

1

Tak.
Warunek na userid != null chyba niepotrzebny.
To też nie powinno być potrzebne s.TenureId == s.Id, jeśli model jest poprawny.
Po co masz metody w CompanyName = x.GetCompanyName(), i w innych miejscach? SQL to obsłuży?
Metoda dostaje predicate A zapytanie to nie używa. Rozumiem, z ebedzie użyty później. Po materializacji?
To tak ma być?
IsPremium = x.SetPremium()

1

Ja bym wręcz zapytał po co Ci repozytorium przy EF? Masz zamiar kiedyś go zmienić? To byłby dla mnie jedyny argument.

5
_flamingAccount napisał(a):

Dlaczego? Pierwszy raz słyszę o takiej zasadzie. Nie mówi że jest zła czy dobra po prostu jestem ciekawy.

Podział na klasy służy zdekomponowaniu dużego problemu na mniejsze, każda klasa udostępnia pewien zakres operacji, które może wykonać, a którego używają klasy leżące wyżej w kompozycji do zrealizowania swojego celu.
To jest dość naturalne, że dekompozycja działa z góry na dół, a nie na boki. Tak działa rzeczywisty świat, np. masz koło składające się z opony i felgi, oraz silnik składający się z tłoków i cylindrów, silnik i koła tworzą samochód. Silnik nie używa koła ani felga nie używa cylindrów, bo dekompozycja działa wertykalnie, a nie horyzontalnie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1