有条件地包括然后包括

时间:2016-04-18 14:52:30

标签: c# entity-framework linq-to-entities entity-framework-core

正如EF-Core中众所周知的那样,没有延迟加载。所以这种意味着我不得不在事后做一些事情。所以,既然我必须思考,那么我也可以尝试正确地做到这一点。

我有一个相当标准的更新查询,但我认为嘿,我并不总是要包含HeaderImagePromoImage FK对象。应该有办法实现这一目标。但我可能无法在以后找到一种方法来执行Include。实际上我想在我真正开始研究这个对象之前就把它包括在内。这样我就可以自动化一些渴望。

ArticleContent ac = _ctx.ArticleContents
    .Include(a=> a.Metadata)
    .Include(a=> a.HeaderImage)
    .Include(a=> a.PromoImage)
    .Single(a => a.Id == model.BaseID);

ac.Title = model.Title;
ac.Ingress = model.Ingress;
ac.Body = model.Body;
ac.Footer = model.Footer;

if (model.HeaderImage != null)
{
    ac.HeaderImage.FileURL = await StoreImage(model.HeaderImage, $"Header_{model.Title.Replace(" ", "_")}_{rand.Next()}");
}
if (model.PromoImage != null)
{
    ac.PromoImage.FileURL = await StoreImage(model.PromoImage, $"Promo_{model.Title.Replace(" ", "_")}_{rand.Next()}");
}

ac.Metadata.EditedById = uId;
ac.Metadata.LastChangedTimestamp = DateTime.Now;

await _ctx.SaveChangesAsync();

EXTRA

要明确的是,这是 EF7(核心),并且我在允许我按需添加的解决方案之后,希望在初始_ctx.ArticleContents.Include(a=> a.Metadata).Single(a => a.Id == model.BaseID).之后

2 个答案:

答案 0 :(得分:1)

我正在使用类似Alexander Derck的解决方案。 (关于评论中提到的例外:ctx.ArticleContents.AsQueryable()也应该有用。)

对于几个CRUD MVC网站,我使用的是BaseAdminController。在派生的具体控制器中,我可以动态添加包含。从BaseAdminController:

// TModel: e.g. ArticleContent
private List<Expression<Func<TModel, object>>> includeIndexExpressionList = new List<Expression<Func<TModel, object>>>();

protected void AddIncludes(Expression<Func<TModel, object>> includeExpression)
{
    includeIndexExpressionList.Add(includeExpression);
}

后来我发现我需要更多的灵活性,所以我添加了一个可查询的。例如。 for ThenInclude()。

private Func<IQueryable<TModel>, IQueryable<TModel>>  IndexAdditionalQuery { get; set; }

protected void SetAdditionalQuery(Func<IQueryable<TModel>, IQueryable<TModel>> queryable)
{
    IndexAdditionalQuery = queryable;
}

这里的索引动作:

public virtual async Task<IActionResult> Index()
{
    // dynamic include:
    // dbset is for instance ctx.ArticleContents
    var queryable = includeIndexExpressionList
        .Aggregate(dbSet.AsQueryable(), (current, include) => current.Include(include));
    if(IndexAdditionalQuery != null) queryable = IndexAdditionalQuery(queryable);
    var list = await queryable.Take(100).AsNoTracking().ToListAsync();
    var viewModelList = list.Map<IList<TModel>, IList<TViewModel>>();

    return View(viewModelList);
}

在具体的控制器中我使用:

AddIncludes(e => e.EventCategory);

SetAdditionalQuery(q => q
    .Include(e => e.Event2Locations)
    .ThenInclude(j => j.Location));

答案 1 :(得分:0)

我会创建一个获取数据的方法,该方法将属性包含在表达式中:

static ArticleContent GetArticleContent(int ID, 
   params Expression<Func<ArticleContent, object>>[] includes)
{
   using(var ctx = new MyContext())
   {
      var acQuery =  _ctx.ArticleContents.Include(a=> a.Metadata);
      foreach(var include in includes)
        acQuery = acQuery.Include(include);
      return acQuery.Single(a => a.Id == model.BaseID);
   }
}

然后在主要方法中:

var ac = GetArticleContent(3, a => a.HeaderImage, a => a.PromoImage);
相关问题