2014-12-05 48 views
0

我正在使用WebAPI和实体框架来构建指向大型MSSQL数据库(〜200个表)的REST API。数据库非常规范化,因此检索对API使用者有用的值需要大量的深入表格。实体框架/ LINQ - 从大型嵌套实体数据集返回数据传输对象

为了向用户返回有用的数据,我采用了使用工厂模式构建模型(或DTO)的方法。但是,我注意到即使所有数据都以良好的格式返回,由于启用了延迟加载,仍然存在性能问题。简而言之,即使在我只返回我需要的数据时,我仍然在查询太多的数据。

于是我使出关闭延迟加载,并试图抢在数据显式地使用包括如下的方法:

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

有没有处理上述情况的模式或做法?我见过一些方法的例子,它允许你传入一个包含语句的数组,但是我想不出一种以优雅,高效,实用的方式处理这个问题的方法。任何输入将不胜感激。

回答

0

您可以使用automapper在实体和DTO之间进行映射,并与Projection一起执行查询并只加载您的DTO需要的列。检查http://automapper.org/https://github.com/AutoMapper/AutoMapper/wiki/Queryable-Extensions

希望有所帮助。

+0

谢谢奥马尔。由于我在观看演示者建议不使用AutoMapper进行ASP WebAPI项目的教程,因为在我的模型中显示自定义数据时可能会出现一些限制,所以我最初对使用AutoMapper犹豫不决。但是,现在我正在给AutoMapper拍摄一笔亏损。 – 2014-12-07 15:30:04

+0

与AutoMapper一起。到目前为止,它对我所需要的工作非常有效。 – 2014-12-18 18:19:54

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来构建您的查询

+0

感谢您的回应!我会给这个镜头... – 2014-12-06 03:35:17

+0

我选择了奥马尔的答案作为我的回应。 Automapper似乎有助于快速完成任务,我希望这是一个长期的解决方案。谢谢! – 2014-12-18 18:19:25