【发布时间】:2015-03-17 16:28:40
【问题描述】:
TL;DR;在大型数据访问层中标准化和抽象 IQueryable 构造的最佳方法是什么?是否可以接受或鼓励扩展?
背景
我们使用带有存储库模式的 Entity Framework 6 作为我们的数据访问层。
为了使我们的数据调用更高效,我们最近开始使用一些结构化的数据传输对象来强制我们只从数据库中提取必要的数据。
例如:我们有一个仪表板,它使用实体映射数据库表的 500 个属性中的 15 个来创建配置文件的分页摘要。
我们直接从SELECT 语句中进行转换,而不是在转换中提取完整实体和映射:
//This is a simplified representation
public List<PersonDashboardDTO> GetPeopleByRangeForDashboard(int start, int length)
{
var returnPeople = new List<PersonDashboardDTO>();
IQueryable<PersonForDashboardDTO> People = databaseContext.Profile
.Where(x => !x.IsDeleted)
.OrderByDescending(x => x.LastName)
.Skip(start).Take(length)
.Select(y => new PersonForDashboardDTO
{
Name = String.Concat(y.FirstName, " ", y.LastName),
Company = y.CompanyContact.Select(x => x.Company.Name).FirstOrDefault(),
SummaryAddress = y.Address.AddressLine1,
City = y.Address.City,
IsEmailOK = y.Notifications.CanSendEmail,
});
returnPeople.AddRange(People);
return returnPeople;
}
虽然这是一个简单的示例,但其中一些 SELECT 映射包含 150 多个属性,并且一遍又一遍地简单地复制和粘贴它违背了我的每一点。
这似乎也是有道理的,因为 IQueryable 在被强制转换为另一个对象 (like .ToList(), or List.AddRange(IQueryable<>) 之前不会执行,因此我们可以创建方法来以更结构化的方式抽象数据访问调用。
我不确定正确的模式是什么,但这是我的想法:
提案:扩展方法
public static IQueryable<PersonDashboardDTO> MapToPersonDashboardDTO(this IQueryable<Profile> profile)
{
return profile.Select(y => new PersonDashboardDTO
{
Name = String.Concat(y.FirstName, " ", y.LastName),
Company = y.CompanyContact.Select(x => x.Company.Name).FirstOrDefault(),
SummaryAddress = y.Address.AddressLine1,
City = y.Address.City,
IsEmailOK = y.Notifications.CanSendEmail
});
}
public static IQueryable<Profile> IsNotDeleted(this IQueryable<Profile> profile)
{
return profile.Where(x => !x.IsDeleted);
}
public static IQueryable<Profile> OrderedByLastName(this IQueryable<Profile> profile)
{
return profile.OrderByDescending(x => x.LastName);
}
public static IQueryable<Profile> TakeRange(this IQueryable<Profile> profile, int start, int length)
{
return profile.Skip(start).Take(length);
}
示例实施
public List<PersonDashboardDTO> GetPeopleByRangeForDashboard(int start, int length)
{
var returnPeople = new List<PersonDashboardDTO>();
IQueryable<PersonDashboardDTO> People = databaseContext.Profile
.IsNotDeleted()
.OrderedByLastName()
.TakeRange(start, length)
.MapToPersonDashboardDTO();
returnPeople.AddRange(People);
return returnPeople;
}
总结
这是一种可接受且可用的模式,可广泛用于标准化我们使用 EF6 进行的查询吗?这似乎是一条不错的路,但我在这里找不到太多标准和做法,希望能有一些新鲜的眼光。
【问题讨论】:
-
如果它对您有用,并且对您有帮助,那就太好了,请继续努力。如果您在实施其中一种方法时遇到特定问题,那么 那 就是您应该询问的问题。
-
@Servy 我认为它会起作用,但是关于正式抽象 LINQ To Entity Queries 的信息很少,这让我停下来。我不知道是否有理由不更多地使用它,但我想把它扔给社区看看是否有人有充分的理由赞成或反对。
-
如果你想知道它是否有效试试。如果有效,很好,如果无效,请解释问题所在,我们可以帮助您。
-
如果我正在寻找更多架构建议@Servy,我应该在哪里发帖?编程击落了它,所以我不知道在哪里发布这样的东西。
-
程序员并没有说它跑题了。他们告诉你不要越过帖子(因为你不应该)。它不是关于 SO 的话题。
标签: c# linq entity-framework linq-to-entities entity-framework-6