如何从包含中选择最后一行

时间:2016-02-15 11:43:07

标签: c# asp.net entity-framework linq entity-framework-core

我正在使用EF 7和MVC 5来创建Web应用程序。我需要从我的数据库中选择所有标题行。

这些行将使用如下所示的类:

public class Log_Header
{
    [Key]
    public int Id { get; set; }
    public string App_Name { get; set; }
    public string App_Url { get; set; }
    public string Submitted_By { get; set; }
    public string App_Contact { get; set; }
    public string App_Description { get; set; }

    public ICollection<Log_Detail> Details { get; set; }
}

如您所见,我有一个Log_Details的集合。

我使用的陈述如下:

public IEnumerable<Log_Header> getLogHeaders()
{
     return _context.LogHeader.Include(t => t.Details).ToList();
}

现在我遇到了问题,我只需要Details的最后一行(最大ID行),但我找不到办法。我尝试了几种没有运气的方法,认为它看起来与此类似:

_context.LogHeader.Include(t => t.Details.Last()).ToList();

我不断得到的错误是:

  

发生了'System.InvalidCastException'类型的异常   EntityFramework.Core.dll但未在用户代码中处理

     

附加信息:无法投射类型的对象   输入'Remotion.Linq.Clauses.Expressions.SubQueryExpression'   'System.Linq.Expressions.MemberExpression'。

如果有人有任何线索,请发表评论或回答,请记住这是使用EF 7。

1 个答案:

答案 0 :(得分:1)

EF不支持只包含First / Last / Whatever行。 EF仅支持包括整个表(即它执行JOIN)。 因此,您将始终获得Log_Header.Count() * Log_Detail().Count()行。 这将花费你很多性能。

更好地将数据加载到数据库的两次往返中。 更好的是:并行和异步执行它们。

public async Task<IEnumerable<Log_Header>> GetHeaderWithLastDetailAsync()
{
    var headerTask = GetLogHeadersAsync();
    var detailTask = GetLastDetailByHeaderIdAsync();

    await Task.WhenAll(headerTask, detailTask).ConfigureAwait(false);

    var header = headerTask.Result;
    var detail = detailTask.Result;

    foreach(var h in header)
    {
        Log_Detail d;
        if(detail.TryGetValue(h.Id, out d)
            h.Details.Add(d);
    }
}

public async Task<IEnumerable<Log_Header>> GetLogHeadersAsync()
{
    using(var context = new MyContext())
    {
        context.Configuration.AutoDetectChangesEnabled = false;
        context.Configuration.ProxyCreationEnabled = false;
        return await context.LogHeader.ToListAsync().ConfigureAwait(false);
    }
}

public async Task<IDictionary<int, Log_Detail>> GetLastDetailByHeaderIdAsync()
{
    using(var context = new MyContext())
    {
        context.Configuration.AutoDetectChangesEnabled = false;
        context.Configuration.ProxyCreationEnabled = false;
        return await context.LogDetail.ToDictionaryAsync(d => d.HeaderId).ConfigureAwait(false);
    }
}