如何避免嵌套使用?
How to avoid nested using?
我编写了一个代码,其中 return 来自 2 个不同数据库的列表。这两个 dbcontext 之间的联合字段是 accountid
和 email
(两者具有相同的值)。由于有 2 个不同的数据库,我无法在 entity framework 中使用 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
}
}
}
我想知道是否可以避免使用嵌套使用并为每个数据库编写一个单独的使用。
你可以做你想做的事。来自内部使用的电子邮件列表会影响来自外部使用的 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 移动到上面 using 下方来执行所有其他逻辑。现在是一个接一个,没有嵌套。
如果您所做的事情不必是事务性的,则首选按顺序访问上下文,因为您不必无缘无故地延长外部上下文的生命周期。 运行 外层的内层延长了外层的使用寿命。
你的代码很复杂。这是我能做的最好的分离和简化:
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;
}
我编写了一个代码,其中 return 来自 2 个不同数据库的列表。这两个 dbcontext 之间的联合字段是 accountid
和 email
(两者具有相同的值)。由于有 2 个不同的数据库,我无法在 entity framework 中使用 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
}
}
}
我想知道是否可以避免使用嵌套使用并为每个数据库编写一个单独的使用。
你可以做你想做的事。来自内部使用的电子邮件列表会影响来自外部使用的 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 移动到上面 using 下方来执行所有其他逻辑。现在是一个接一个,没有嵌套。
如果您所做的事情不必是事务性的,则首选按顺序访问上下文,因为您不必无缘无故地延长外部上下文的生命周期。 运行 外层的内层延长了外层的使用寿命。
你的代码很复杂。这是我能做的最好的分离和简化:
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;
}