Как избежать вложенного использования? - PullRequest
0 голосов
/ 01 мая 2019

Я написал код, который возвращает список из 2 разных баз данных.Совместное поле между этими буквами dbcontext равно accountid и email (оба имеют одинаковое значение).Поскольку есть две разные базы данных, я не могу использовать объединение в рамках сущностей.Так что я использовал вложенное использование и для каждого блока.Вот мой код:

namespace AdminMvc.Components.BankDepositHistory
{
    public class BankDepositHistoryHelper
    {
        public static List<BankDepositHistoryItemDto> GetChangeRequestsList(int skip, int take, out int total, string name, string email, AvailableBankDepositStates state)
        {
            using (var myketAdsDB = new MyketAdsEntities())
            {
                using (var myketDB = new MyketReadOnlyDb())
                {
                    #region DefaultQuery
                    var bankDepositHistories = myketAdsDB.BankDepositHistories.AsQueryable();
                    #endregion
                    #region Filtering
                    if (!string.IsNullOrWhiteSpace(name))
                    {
                        var emails = myketDB.AppDevelopers
                            .Where(n => n.RealName.Contains(name))
                            .Select(e => e.Email).ToList();
                        // emails.Add(email);
                        if (emails.Count > 0)
                        {
                            bankDepositHistories = bankDepositHistories.Where(e => emails.Contains(e.AccountId));
                        }
                    }
                    if (!string.IsNullOrWhiteSpace(email))
                    {
                        bankDepositHistories = bankDepositHistories.Where(a => a.AccountId.Contains(email));
                    }
                    if (state != AvailableBankDepositStates.All)
                    {
                        bankDepositHistories = state == AvailableBankDepositStates.Success ?
                        bankDepositHistories.Where(x => x.State == AvailableBankDepositStates.Success.ToString()) :
                        bankDepositHistories.Where(x => x.State == AvailableBankDepositStates.Fail.ToString());
                    }
                    else
                    {
                        bankDepositHistories = bankDepositHistories.
                            Where(x => x.State != BankDepositState.Start.ToString());
                    }
                    #endregion
                    #region GetingTotalpages
                    total = bankDepositHistories.Count();
                    #endregion
                    #region Pagination
                    var pageResult = bankDepositHistories.OrderByDescending(ba => ba.CreationDate).Skip(skip).Take(take).ToList();
                    #endregion
                    #region FillingDomainObjects
                    var emailFilter = pageResult.Select(r => r.AccountId).ToList();
                    var developers = myketDB.AppDevelopers.Where(a => emailFilter.Contains(a.Email)).
                        Select(r => new { r.RealName, r.Email }).ToList();
                    var result = pageResult
                        .Select(b => new BankDepositHistoryItemDto()
                        {
                            Id = b.Id,
                            AccountId = b.AccountId,
                            Amount = b.Amount,
                            ClientIp = b.ClientIp,
                            State = (BankDepositState)Enum.Parse(typeof(BankDepositState), b.State, true),
                            ReturnUrl = b.ReturnUrl,
                            AdditionalData = b.AdditionalData,
                            Gateway = b.Gateway,
                            CreationDate = b.CreationDate,
                            PaymentRefNumber = b.PaymentRefNumber,
                            Uuid = b.Uuid,
                        }).ToList();
                    foreach (var bankDepositHistory in result)
                    {
                        foreach (var developer in developers)
                        {
                            if (bankDepositHistory.AccountId == developer.Email)
                            {
                                bankDepositHistory.RealName = developer.RealName;
                            }
                        }
                    }
                    return result;
                    #endregion
                }
            }
        }

Мне было интересно, можно ли избежать использования вложенного использования и написать отдельное использование для каждой базы данных.

Ответы [ 2 ]

1 голос
/ 01 мая 2019

Ваш код очень запутанный. Это лучшее, что я мог сделать, чтобы отделить и упростить:

public static List<BankDepositHistoryItemDto> GetChangeRequestsList(int skip, int take, out int total, string name, string email, AvailableBankDepositStates state)
{
    var statesFilter = new Dictionary<AvailableBankDepositStates, Func<IQueryable<BankDepositHistory>, IQueryable<BankDepositHistory>>>()
    {
        { AvailableBankDepositStates.All, bdh => bdh.Where(x => x.State != BankDepositState.Start.ToString()) },
        { AvailableBankDepositStates.Success, bdh => bdh.Where(x => x.State == AvailableBankDepositStates.Success.ToString()) },
        { AvailableBankDepositStates.Fail, bdh => bdh.Where(x => x.State == AvailableBankDepositStates.Fail.ToString()) },
    };

    List<string> emails = new List<string>();
    ILookup<string, string> developers = null;

    using (var myketDB = new MyketReadOnlyDb())
    {
        if (!string.IsNullOrWhiteSpace(name))
        {
            emails = myketDB.AppDevelopers.Where(n => n.RealName.Contains(name)).Select(e => e.Email).ToList();
        }
        developers = myketDB.AppDevelopers.ToLookup(x => x.Email, x => x.RealName);
    }

    using (var myketAdsDB = new MyketAdsEntities())
    {
        var bankDepositHistories = myketAdsDB.BankDepositHistories.AsQueryable();
        if (emails.Count() > 0)
        {
            bankDepositHistories = bankDepositHistories.Where(e => emails.Contains(e.AccountId));
        }
        if (!string.IsNullOrWhiteSpace(email))
        {
            bankDepositHistories = bankDepositHistories.Where(a => a.AccountId.Contains(email));
        }
        bankDepositHistories = statesFilter[state](bankDepositHistories);

        total = bankDepositHistories.Count();

        var result =
            bankDepositHistories
                .OrderByDescending(ba => ba.CreationDate)
                .Skip(skip)
                .Take(take)
                .ToList()
                .Select(b => new BankDepositHistoryItemDto()
                {
                    Id = b.Id,
                    AccountId = b.AccountId,
                    Amount = b.Amount,
                    ClientIp = b.ClientIp,
                    State = (BankDepositState)Enum.Parse(typeof(BankDepositState), b.State, true),
                    ReturnUrl = b.ReturnUrl,
                    AdditionalData = b.AdditionalData,
                    Gateway = b.Gateway,
                    CreationDate = b.CreationDate,
                    PaymentRefNumber = b.PaymentRefNumber,
                    Uuid = b.Uuid,
                    RealName = developers[b.AccountId].LastOrDefault(),
                }).ToList();

        return result;
    }
}

Вот код, который мне пришлось безопасно написать для рефакторинга:

public enum AvailableBankDepositStates
{
    All, Success, Fail
}

public enum BankDepositState
{
    Start
}

public class BankDepositHistoryItemDto
{
    public string AccountId;
    public BankDepositState State;
    public DateTime CreationDate;
    public string RealName;
}

public class MyketAdsEntities : IDisposable
{
    public IEnumerable<BankDepositHistory> BankDepositHistories;

    public void Dispose()
    {
        throw new NotImplementedException();
    }
}

public class MyketReadOnlyDb : IDisposable
{
    public IEnumerable<AppDeveloper> AppDevelopers;

    public void Dispose()
    {
        throw new NotImplementedException();
    }
}

public class BankDepositHistory
{
    public string AccountId;
    public string State;
    public DateTime CreationDate;
}

public class AppDeveloper
{
    public string RealName;
    public string Email;
}
1 голос
/ 01 мая 2019

Вы можете делать то, что вы просите.Список писем из внутреннего использования влияет на bankDepositHistories, которые из внешнего использования, но этот внешний запрос не выполняется до позже.(Кроме того, исходное внутреннее использование не зависит от чего-либо во внешнем, поэтому может быть перемещено за его пределы).

Итак, сначала получите список адресов электронной почты, используя myketDB:

List<Email> emails = new List<Email>();
using (var myketDB = new MyketReadOnlyDb())
{
    if (!string.IsNullOrWhiteSpace(name))
    {
        emails = myketDB.AppDevelopers
            .Where(n => n.RealName.Contains(name))
            .Select(e => e.Email).ToList();
    }
}

// original outer using is now after the above

Затем выполните всю другую логику, переместив внешнее использование myketAdsDB в исходном коде ниже использования выше.Теперь это один за другим, а не вложенный.

Если то, что вы делаете, не обязательно должно быть транзакционным, предпочтительным является последовательный доступ к контекстам, поскольку вам не нужно расширять время жизни внешнего контекста длянет причин.Управление внутренним внутри внешнего продлевает жизнь внешнего.

...