如何避免嵌套使用?



我写了一个代码,它从 2 个不同的数据库返回一个列表。这些拖曳数据库上下文之间的联合字段是accountidemail(两者都具有相同的值)。由于有 2 个不同的数据库,因此我无法在实体框架中使用 join。所以我为每个块使用嵌套的 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
}
}
}

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

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

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

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

如果您正在执行的操作不必是事务性的,则最好按顺序访问上下文,因为您不必无缘无故地延长外部上下文的生存期。在内部运行外部可以延长外部的使用寿命。

最新更新