我正在使用WebAPI和Entity Framework构建一个指向大型MSSQL数据库(~200个表)的REST API。数据库非常规范化,因此检索对API的使用者有用的值需要大量深入到表中。
为了将有用的数据返回给消费者,我采用了使用工厂模式构建模型(或DTO)的方法。但是,我注意到即使所有数据都以漂亮的格式返回,但由于启用了延迟加载,因此存在性能问题。简而言之,即使在我只返回我需要的数据时,我也在查询过多的数据。
所以我使用了关闭延迟加载并尝试使用Include方法显式获取数据:
var accessions = db.AccessionParties
.Include(ap => ap.Accession.AccessionParties.Select(ap2 => ap2.Party))
.Include(ap => ap.Accession.AccessionParties.Select(ap2 => ap2.AccessionPartyPurposes.Select (app => app.PartyAccessionPurposeType)))
.Include(ap => ap.Accession.AccessionAnimals.Select(x => x.AnimalInformationType))
.Include(ap => ap.Accession.AccessionAnimals.Select(x => x.Specimens.Select(y => y.AccessionTestRequestSpecimens.Select(z => z.AccessionTestRequest.LabTestOffering.TestOffering))))
.ToList()
.Select(a => modelFactory.CreateAccessionModel(a.Accession));
下面是我用来生成模型的工厂方法的示例,其中包括嵌套的工厂方法以及我的相关数据实体的形状。
public AccessionModel CreateAccessionModel(Accession accession)
{
return new AccessionModel()
{
AccessionKey = accession.AccessionKey,
SubmittedDate = accession.SubmittedDate,
Parties = accession.AccessionParties
.Select(accessionParty => new { accessionParty = accessionParty, accessionParty.Party })
.Select(accessionParty => CreatePartyModel(accessionParty.Party)),
Animals = accession.AccessionAnimals.Select(accessionAnimal => CreateAccessionAnimalModel(accessionAnimal))
};
}
是否有处理上述情况的模式或做法?我已经看到了一些允许你传入一系列include语句的方法的例子,但是我想不出一种以优雅,高效,实用的方式处理它的方法。任何输入都将非常感激。
答案 0 :(得分:0)
我在我的一个方法中这样做,传递一个像这样的字符串数组(它很难看,因为我使用反射来获取属性名称,但希望你能得到这个想法)
private IQueryable<T> AddIncludes<T>(IDatabase db) // my Entity context class implements IDatabase
{
var props = typeof(IDatabase).GetProperties(BindingFlags.Public|BindingFlags.Instance);
IQueryable<T> ret = null;
foreach (var prop in props)
{
if (prop.PropertyType.Name == "IDbSet`1" &&
prop.PropertyType.GetGenericArguments()[0] == typeof(T))
{
ret = (IQueryable<T>)prop.GetValue(db, null);
break;
}
}
var includes = GetIncludes((DbContext)db, typeof(T)); // this returns an IEnumerable<string> of the includes
foreach (string include in includes) // replace string with a lambda
{
ret = ret.Include(include); // this is where the includes are added
}
return ret;
}
private ICollection<T> LoadObjectGraph<T>(IDatabase db, Func<T, bool> filter)
{
var queryableWithIncludesAdded = AddIncludes<T>(db);
return queryableWithIncludesAdded.Where(filter).ToList();
}
您可以使用相同的技术传递lambdas来构建查询
,而不是使用字符串答案 1 :(得分:0)
您可以使用automapper在实体和DTO之间进行映射,并与Projection一起执行查询并仅加载DTO所需的列。查看http://automapper.org/和https://github.com/AutoMapper/AutoMapper/wiki/Queryable-Extensions
希望有所帮助。