#c# #linq
#c# #linq
Вопрос:
Внутри сервиса у меня есть метод, который собирает данные из разных таблиц и объединяет их в один Dto, accountDto
.
Моя самая большая проблема заключается в том, что в разных таблицах нет связей внешнего ключа. Таким образом, я должен создавать свои собственные отношения.
Первые два метода GetAccount
и GetPerson
просто получение данных из отдельных таблиц с помощью методов репозитория. Две таблицы связаны общим TrinId
. Последний метод GetRoleDtos
намного сложнее и включает в себя несколько объединений, как показано ниже. Этот последний бит данных связан AccountId
.
Этот единственный метод, похоже, попадает в базу данных несколько раз. Как я могу минимизировать количество обращений и повысить скорость, следуя тому же шаблону службы / репозитория?
public AccountDto GetAccountDto(int accountId)
{
try
{
Account account = _unitOfWork.AccountRepository.GetAccount(accountId);
AccountDto accountDto = account == null ? new AccountDto() : new AccountDto
{
AccountId = account.AccountId,
UserName = account.UserName,
TrinId = account.TrinId,
LastName = account.LastName,
FirstName = account.FirstName
};
Person person = _unitOfWork.AccountRepository.GetPerson(accountDto.TrinId);
accountDto.Person = person == null ? new PersonDto() : new PersonDto
{
Id = person.Id,
TrinId = person.TrinId,
AccountId = person.AccountId,
LastName = person.LastName,
FirstName = person.FirstName,
MiddleName = person.MiddleName,
Gender = person.Gender,
BirthDate = person.BirthDate
};
accountDto.Roles = _unitOfWork.AccountRepository.GetRoleDtos(accountId).ToList();
return accountDto;
}
catch (Exception ex)
{
Log.Error(ex);
throw;
}
}
public IQueryable<RoleDto> GetRoleDtos(int accountId)
{
var userModuleRoles = from account in _model.Accounts
join userRight in _model.UserRights on account.AccountId equals userRight.AccountId
join role in _model.Roles on userRight.RoleId equals role.Id
join organization in _model.Organizations on userRight.OrganizationId equals organization.Id
join module in _model.Modules on role.ModuleId equals module.Id
where (account.IsApproved == true amp;amp; userRight.Status == 1 amp;amp; account.AccountId == accountId)
select new RoleDto
{
Id = role.Id,
RoleName = role.Name,
AccountId = account.AccountId,
OrganizationId = organization.Id,
OrganizationName = organization.Name,
ModuleId = module.Id,
ModuleName = module.Name
};
return userModuleRoles;
}
Здесь была моя первоначальная попытка выполнить запрос «все в одном». Это сработало, но у меня возникли проблемы с получением List<RoleDto>
. Как я могу также получить список ролей Dto?
Запрос, который я использую сейчас, показан в GetRoleDtos
методе, но его необходимо включить в этот запрос. У меня было одно частично работающее решение, но сейчас оно удалено. Я отказался от этого, потому что, когда не было записей RoleDto, весь запрос возвращал null. В этом случае мне все равно понадобится заполненный AccountDto с пустой коллекцией RoleDto . Я считаю, что мне нужно использовать DefaultIfEmpty
для получения и очистки коллекции, но именно в этот момент я сдался, потому что запрос становился громоздким. 🙁
return account;
}
public AccountDto GetAccountDto(int accountId)
{
return (from a in _model.Accounts
join p in _model.People on a.TrinId equals p.TrinId into perJoin
from per in perJoin.DefaultIfEmpty()
where a.AccountId == accountId
select new AccountDto
{
AccountId = a.AccountId,
UserName = a.UserName,
TrinId = a.TrinId,
LastName = a.LastName,
FirstName = a.FirstName,
Person = new PersonDto
{
Id = per.Id,
LastName = per.LastName,
FirstName = per.FirstName,
MiddleName = per.MiddleName,
Gender = per.Gender,
BirthDate = per.BirthDate
}
}).FirstOrDefault();
}
Ответ №1:
Я бы предложил создать новый объект для возврата из вашего репозитория. Этот новый объект будет чем-то вроде, и это всего лишь неполная идея:
public class AccountInfo {
public int AccountId { get; set; }
public string UserName { get; set; }
public int TrinId { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public Person PersonInfo { get; set; }
public List<Roles> AccountRoles { get; set; }
}
Затем создайте в своем репозитории единый метод, который заполняет все необходимые свойства, поскольку вы можете четко получить Account
и на List<Roles>
основе accountId
, а затем присоединиться к вашей персональной информации на основе этого TrinId
. Я оставлю запрос на ваше усмотрение.
Комментарии:
1. Твердый ответ, я нахожу, что многие люди чувствуют при использовании сервиса / репозитория, что каждый репозиторий должен возвращать только один объект, для которого создан репозиторий. В то время как на самом деле было бы очень неуправляемо и неэффективно создавать систему, которая строго придерживается этого.
2. Да, я изначально начал пробовать что-то подобное, но запрос очень быстро усложнился…
3. @navig8tr это нормально для имен. Я предполагаю, что в вашем
Person
классе будут имена и фамилии. Просто заполните их также из вашего запроса.4. Я включил свою первую попытку всеохватывающего запроса. Я назвал его классом
AccountDto
, а неAccountInfo
но идея та же.5. @navig8tr Я думаю, что вы сталкиваетесь с вопросом-scope-creep. На ваш первоначальный вопрос
How can I minimize the number of hits and improve speed, while following this same Service/Repository pattern?
был дан ответ. Сам запрос звучит как другой.