【问题标题】:EF & linq - many to many relationshipEF & linq - 多对多关系
【发布时间】:2011-01-19 14:06:36
【问题描述】:

我有 3 个表,它们之间存在多对多关系

用户:ID (PK)、姓名

用户课程:用户 ID (PK)、课程 ID (PK)

课程:ID (PK)、名称

我需要编写一个 linq 查询来选择用户 X 的所有课程名称并在 IEnumerable 中返回,但我无法让它工作。

编辑:

public IEnumerable<Courses> GetCourses
        {
            get
            {
                return (from a in _entities.Users.Include("Courses")
                        where a.Id == this.Id
                        select a.Courses.AsEnumerable()
                        );
            }
        }

非常感谢任何帮助

谢谢

【问题讨论】:

  • 我刚刚添加了代码
  • 运行它时发生了什么?您是否收到错误的数据?抛出异常?
  • 错误 31 无法将类型 'System.Linq.IQueryable>' 隐式转换为 'System.Collections.Generic.IEnumerable'。存在显式转换(您是否缺少演员表?)
  • 这与我在下面观察到的嵌套问题一致。注意嵌套的&lt; &gt; 括号。

标签: .net linq entity-framework


【解决方案1】:

你有点不清楚出了什么问题,但看起来它会产生一个IEnumerable&lt;IEnumerable&lt;Courses&gt;&gt; 类型。如果你正在寻找一个扁平化 IEnumerable&lt;Courses&gt;,我认为你是这样的,你需要这样的东西:

    public IEnumerable<Courses> GetCourses
    {
        get
        {
            var query = from a in _entities.Users.Include("Courses")
                        where a.Id == this.Id
                        select a;

            return query.FirstOrDefault().Courses;
        }
    }

编辑:为避免 NullReferenceException,请尝试以下操作:

    public IEnumerable<Courses> GetCourses
    {
        get
        {
            var query = from a in _entities.Users.Include("Courses")
                        where a.Id == this.Id
                        select a.Courses; //note the difference

            return query.SelectMany(i => i);
        }
    }

请注意,有不止一种方法可以做到这一点;例如,您还可以使用:

            var query = from a in _entities.Users.Include("Courses")
                        where a.Id == this.Id
                        select a;

            var user = query.FirstOrDefault();

            return user == null 
                      ? user.Courses
                      : null;

如果SelectMany 版本仍然导致 NullReferenceException,请改用它。我认为不应该,但我没有测试过。您指出 Rup 的解决方案已经做到了这一点,并且他使用 SelectMany 的方式与我非常相似,所以最后一个版本很安全。

【讨论】:

  • 它不允许我使用 .FirstOrDefault()
  • 查询是什么类型 - IEnumerable&lt;User&gt;?我原以为 FirstOrDefault() 会没问题,除了在 null 情况下 - 你会得到什么错误? return query.SelectMany(a =&gt; a.Courses); 会起作用吗?
  • 对不起,我的错误,它允许我使用 FirstOrDefault()。让我运行一下看看...
  • 嗨 Rup,这可行,但前提是有与用户相关的课程。否则,它会引发错误:“对象引用未设置为对象的实例。”有没有办法解决?谢谢
  • 嗯,这很奇怪 - 通常,如果您仍在 SQL 层中执行此操作,则无需担心 null 检查。您可以尝试.Where(a =&gt; a.Courses != null).SelectMany(a =&gt; a.Courses) 看看是否有帮助,但我仍然希望它在数据库中执行这些操作 - 可能值得尝试找出哪个操作触发了代码中对象的切换。 (附注:因为这不是对我的回答的回复,所以您应该像 Twitter 一样写 @ - 即 @Rup - 所以我会收到回复通知。但是,您在下面对我的回答的回复会在没有 @ 的情况下向我发送通知。)跨度>
【解决方案2】:

对我来说,这或多或少看起来不错。如果您只删除 .AsEnumerable(),这不起作用吗?我认为你不需要那个。

我更喜欢 LINQ 扩展方法调用语法;我认为这样做的方法是

var courses = _entities.Users.Include("Courses")
                       .Where(a => a.Id == this.Id)
                       .SelectMany(a => a.Courses);

额外的.Select(c =&gt; c.Name) 仅用于课程名称。

【讨论】:

  • 不,无论是否使用 AsEnumerable(),它都会引发此错误:错误 31 无法隐式转换类型 'System.Linq.IQueryable>' 到 'System.Collections.Generic.IEnumerable'。存在显式转换(您是否缺少演员表?)
  • 好的,抱歉。我在我当前的项目中选择了多对多关系,这工作正常,尽管它是映射在属性设计器中显示为 1 对 * 的关系 - 我不确定我是否有一个真实的* -to- * 在这里玩。
  • 在我的实体设计器中找到了一个 * -to - * ,这对我来说仍然有效,抱歉,对于这种关系。即使在 SelectMany 之后,您的错误看起来仍然有一个课程列表列表(!)。我想你可以用第二个 SelectMany 强行解决这个问题,尽管最好了解它的来源。
  • 嗨 Rup,这确实有效,但正如我在另一条评论中所说,如果没有为用户分配课程,它就会中断。有没有办法解决这个问题?
【解决方案3】:

试试看

from b in _entities.Users.Include("UserCourses") on a.UserID equals this.ID
join c in _entities.Users.Include("Courses") on b.CourseID equals c.ID
select c.name

【讨论】:

  • 我怀疑 EF 已将 UserCourses 吸收到关系中 - 他将只有一个导航属性 Courses
【解决方案4】:

直接用join查询联结表:

            var courses = (from uc in _entities.UserCourses
                           inner join c in _entities.Courses on uc.CourseId equals c.Id
                           inner join u in _entities.Users on uc.UserId equals u.Id
                           where uc.UserId equals u.Id
                           select c).ToList();

【讨论】:

    猜你喜欢
    • 2021-10-21
    • 1970-01-01
    • 2021-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-29
    • 2018-06-02
    • 1970-01-01
    相关资源
    最近更新 更多