【问题标题】:Retrieving data from multiple tables with .Include()使用 .Include() 从多个表中检索数据
【发布时间】:2016-12-29 06:21:27
【问题描述】:

这是检索数据的正确方法吗?这是我能够为用户检索具有相应类别的所有任务的唯一方法。如果我在 .ToList() 之前有 where 子句,它会给我一个例外(ApplicationUser 将为空)。我不喜欢这种方法的地方是我先从数据库中检索所有数据,然后再将其解析得更远,只为特定用户返回数据。在某些情况下, .Include() 方法不能像我想象的那样工作。

public IEnumerable<Task> GetAllTasksForUser(string username)
    {
        return _db.Tasks
                .Include(t => t.Category)
                .Include(t => t.Category.ApplicationUser)
                .ToList()
                .Where(t => t.Category.ApplicationUser.UserName == username);
    }

这个出错了:

try
        {
            var x = _db.Tasks
                .Include(t => t.Category)
                .Include(t => t.Category.ApplicationUser)
                .Where(t => t.Category.ApplicationUser.UserName == username)
                .ToList();

        }
        catch(Exception ex)
        {

        }

从 Profiler 检索到的生成的工作 sql 语句。当我运行生成的查询时,它会检索数据,但它会使用 linq 引发提到的异常。这个 .Include() 正在杀死我:

> SELECT [t].[TaskId], [t].[CategoryId], [t].[Description], [t].[Name], [t].[Timestamp], [t.Category].[CategoryId], [t.Category].[Description], [t.Category].[Name], [t.Category].[Timestamp], [t.Category].[UserId], [t.Category.ApplicationUser].[Id], [t.Category.ApplicationUser].[AccessFailedCount], [t.Category.ApplicationUser].[ConcurrencyStamp], [t.Category.ApplicationUser].[Email], [t.Category.ApplicationUser].[EmailConfirmed], [t.Category.ApplicationUser].[LockoutEnabled], [t.Category.ApplicationUser].[LockoutEnd], [t.Category.ApplicationUser].[NormalizedEmail], [t.Category.ApplicationUser].[NormalizedUserName], [t.Category.ApplicationUser].[PasswordHash], [t.Category.ApplicationUser].[PhoneNumber], [t.Category.ApplicationUser].[PhoneNumberConfirmed], [t.Category.ApplicationUser].[SecurityStamp], [t.Category.ApplicationUser].[TwoFactorEnabled], [t.Category.ApplicationUser].[UserName], [c].[CategoryId], [c].[Description], [c].[Name], [c].[Timestamp], [c].[UserId], [a].[Id], [a].[AccessFailedCount], [a].[ConcurrencyStamp], [a].[Email], [a].[EmailConfirmed], [a].[LockoutEnabled], [a].[LockoutEnd], [a].[NormalizedEmail], [a].[NormalizedUserName], [a].[PasswordHash], [a].[PhoneNumber], [a].[PhoneNumberConfirmed], [a].[SecurityStamp], [a].[TwoFactorEnabled], [a].[UserName], [c0].[CategoryId], [c0].[Description], [c0].[Name], [c0].[Timestamp], [c0].[UserId]
FROM [Tasks] AS [t]
INNER JOIN [Categories] AS [t.Category] ON [t].[CategoryId] = [t.Category].[CategoryId]
LEFT JOIN [AspNetUsers] AS [t.Category.ApplicationUser] ON [t.Category].[UserId] = [t.Category.ApplicationUser].[Id]
INNER JOIN [Categories] AS [c] ON [t].[CategoryId] = [c].[CategoryId]
LEFT JOIN [AspNetUsers] AS [a] ON [c].[UserId] = [a].[Id]
INNER JOIN [Categories] AS [c0] ON [t].[CategoryId] = [c0].[CategoryId]
ORDER BY [t.Category].[UserId]

这一项有效,但结果不包括 Category 和 ApplicationUser:

return _db.Tasks
.Where(t => t.Category.ApplicationUser.UserName == username)
.ToList();

还有我的模特:

 public class Task
{
    [Key]
    public int TaskId { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public DateTime Timestamp { get; set; }
    public int CategoryId { get; set; }

    public virtual Category Category { get; set; }
}

    public class Category
{
    [Key]
    public int CategoryId { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public DateTime Timestamp { get; set; }

    public string UserId { get; set; }
    [ForeignKey("UserId")]
    public virtual ApplicationUser ApplicationUser { get; set; }

    public virtual ICollection<Task> Tasks { get; set; }
}

public class ApplicationUser : IdentityUser
{
    public virtual ICollection<Category> Categories { get; set; }
}

错误堆栈跟踪:

在 lambda_method(Closure , InternalEntityEntry ) 在 Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SimpleNonNullableDependentKeyValueFactory1.TryCreateFromCurrentValues(InternalEntityEntry entry, TKey& key) at Microsoft.EntityFrameworkCore.Query.Internal.WeakReferenceIdentityMap1.CreateIncludeKeyComparer(INavigation 导航,InternalEntityEntry 条目) 在 Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.IncludeCore(对象实体,INavigation 导航) 在 Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.Include(QueryContext queryContext,对象实体,IReadOnlyList1 navigationPath, IReadOnlyList1 relatedEntitiesLoaders,Int32 currentNavigationIndex,布尔查询状态管理器) 在 Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.Include(QueryContext queryContext,对象实体,IReadOnlyList1 navigationPath, IReadOnlyList1 relatedEntitiesLoaders,布尔查询状态管理器) 在 Microsoft.EntityFrameworkCore.Query.Internal.GroupJoinInclude.Include(对象实体) 在 Microsoft.EntityFrameworkCore.Query.Internal.GroupJoinInclude.Include(对象实体) 在 Microsoft.EntityFrameworkCore.Query.QueryMethodProvider.<_groupjoin>d__264.MoveNext() at System.Linq.Enumerable.<SelectManyIterator>d__1633.MoveNext() 在 System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext() at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.<_TrackEntities>d__152.MoveNext() 在 Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor1.EnumeratorExceptionInterceptor.MoveNext() at System.Collections.Generic.List1..ctor(IEnumerable1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable1 源) 在 .GetAllTask​​sForUser(String username) in :line 31

【问题讨论】:

  • 如果我在 .ToList() 之前有 where 子句,它会给我一个例外(ApplicationUser 将为空) 不,它不会“给你一个例外”。在实现查询之前,您编写的所有内容都只是用于生成 SQL 查询的元数据。这个Where 应该在ToList 之前。 Include 与查询无关,但控制将在您的对象中填充的内容,同样仅在查询具体化时。
  • CategoryApplicationUserLists 还是单个对象?
  • 它给了我例外,就像我提到的那样,它说“对象引用未设置为对象的实例。” (它适用于 ApplicationUser)。我认为你是不正确的,那是 .Include() 造成的。
  • 假设你得到一个异常,你能发布异常堆栈跟踪吗?
  • 当然,刚刚更新了我的问题

标签: linq lambda entity-framework-core


【解决方案1】:

您是否错过了 Category 实体中 ApplicationUser 的外键?您刚刚定义了 ApplicationUser 的导航属性。尝试设置这种关系; IMO,一旦设置此关系,出错的查询将正常工作。

【讨论】:

  • 好点,但它并没有解决我的问题。我已经更新了我的模型并重新生成了我的表,而现在我的类别中有用户外键,仍然是同样的问题。
  • @lucas 但我仍然没有在您的实体中看到该外键。
  • 我会更新我的问题...完成。数据库数据已正确填充,我在表中有类别的相应 userId
  • 您的应用程序用户主键为“字符串”的任何具体原因?如果您不介意,您可以尝试 integer 和 DbGenerated 选项 Identity 吗?不确定字符串是否对主键有意义。
  • 它是 MVC 应用程序,Microsoft 使用字符串作为用户 ID 主 ID。 GUID 是最安全的,但不一定是最快的。这在这里不是问题,因为数据库中的所有内容都填充得很好
猜你喜欢
  • 2017-03-23
  • 1970-01-01
  • 2019-04-30
  • 1970-01-01
  • 1970-01-01
  • 2011-12-23
  • 2013-03-26
相关资源
最近更新 更多