【问题标题】:How to avoid nested using?如何避免嵌套使用?
【发布时间】:2019-05-01 08:24:36
【问题描述】:

我编写了一个代码,它返回来自 2 个不同数据库的列表。这两个 dbcontext 之间的联合字段是 accountidemail(两者具有相同的值)。由于有 2 个不同的数据库,我不能在实体框架中使用连接。所以我对每个块都使用了嵌套的 using 和。这是我的代码:

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
                }
            }
        }

我想知道是否可以避免使用嵌套 using 并为每个数据库编写一个单独的 using。

【问题讨论】:

  • 为什么要拥有两个单独的using 语句?这能给你带来什么价值?
  • 您可以使用 2 个(或更多)using 语句,一个在另一个之下,而无需使用左括号
  • @Enigmativity 因为我的老板想要它:)。查询没有问题。查询对象的返回列表。
  • @AliEshghi - 为什么你的老板想要它?他/她肯定已经解释了原因。
  • @AliEshghi - 除非您知道自己正在创建内存问题,否则可能不值得优化。但是,您的代码确实很复杂。如果我是你的经理,我希望你能显着简化代码,而这只是来自维护 POV。我正在尝试重构您的代码,但这很难,真的很难。

标签: c# sql asp.net-mvc entity-framework using


【解决方案1】:

您的代码非常复杂。这是我能做的最好的分离和简化:

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;
}

【讨论】:

    【解决方案2】:

    可以做你所要求的。来自内部使用的电子邮件列表会影响来自外部使用的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 的外部使用移动到上述使用下方来执行所有其他逻辑。现在是一个接一个,没有嵌套。

    如果您所做的事情不必是事务性的,则优先顺序访问上下文,因为您不必无缘无故地延长外部上下文的生命周期。在外部运行内部内部可以延长外部的寿命。

    【讨论】:

    • 我觉得你说得对,让我试试,然后我会标记为答案。
    猜你喜欢
    • 1970-01-01
    • 2012-10-05
    • 2013-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-25
    • 2023-04-10
    相关资源
    最近更新 更多