【问题标题】:EF LInq Left outer join sorted taking fistEF LInq 左外连接排序采取拳头
【发布时间】:2016-01-21 16:32:45
【问题描述】:

我有这个左外连接查询

var queryString = (from entity in _dbContext.Links
                   from translations in _dbContext.LinksTrs.Where(p => p.LinkId == entity.Id).OrderBy(p => p.LanguageCode).Take(1).DefaultIfEmpty()
                   select new LinksAdminListModel()
                   {
                     Id = entity.Id,
                     Name = (translations == null) ? "" : translations.Name,
                     Url = entity.Url,
                     Active = entity.Active
                   });

如您所见,当我返回所有左侧行时,​​我只从查询的右侧获取一行。

我需要的是,而不是仅按 LanguageCode 排序,我需要告诉查询先按特定的 LanguageCode 排序,然后再按其余部分。

如果我添加这个:

.OrderBy(p => (p.LanguageCode == currentLanguage) ? 0 : 1)

其中 currentLanguage 只是一个包含语言“en”、“fr”的字符串... 所以查询是:

var queryString = (from entity in _dbContext.Links
                   from translations in _dbContext.LinksTrs.Where(p => p.LinkId == entity.Id).OrderBy(p => (p.LanguageCode == currentLanguage) ? 0 : 1).Take(1).DefaultIfEmpty()
                   select new LinksAdminListModel()
                   {
                     Id = entity.Id,
                     Name = (translations == null) ? "" : translations.Name,
                     Url = entity.Url,
                     Active = entity.Active
                   });

我收到以下错误: “‘where 子句’中的未知列‘Extent1.Id’”

我需要帮助,因为如果当前语言存在,我需要返回当前语言,如果不存在的话。

谢谢。

编辑

问题是 ORDER 与 TAKE(1) 的组合,但我确实需要只取第一个...

编辑 2

问题似乎是我在上面评论的......这是我正在使用的查询:

            var queryString = (from entity in _dbContext.Links
                               from translations in _dbContext.LinksTrs.Where(p => p.LinkId == entity.Id).OrderByDescending(p => p.LanguageCode == currentLanguage).ThenBy(p => p.LanguageCode).Take(1)
                               select new LinksAdminListModel()
                               {
                                   Id = entity.Id,
                                   Name = (translations == null) ? "" : translations.Name,
                                   Url = entity.Url,
                                   Active = entity.Active
                               });

这是它正在生成的 SQL...以防有人在这里看到一些东西:

SELECT
`Apply1`.`Id`, 
`Apply1`.`Name`, 
`Apply1`.`Url`, 
`Apply1`.`Active`
FROM (SELECT
`Extent1`.`Id`, 
`Extent1`.`OrderPos`, 
`Extent1`.`Url`, 
`Extent1`.`Active`, 
`Extent1`.`DateCreated`, 
`Extent1`.`DateModified`, 
`Extent1`.`UserIdModified`, 
(SELECT
`Project1`.`C1`
FROM (SELECT
CASE WHEN ((`Extent2`.`LanguageCode` = 'es-ES') OR   ((`Extent2`.`LanguageCode` IS  NULL) AND ('es-ES' IS  NULL))) THEN (1)  WHEN (NOT ((`Extent2`.`LanguageCode` = 'es-ES') AND ((CASE WHEN (`Extent2`.`LanguageCode` IS  NULL) THEN (1)  ELSE (0) END) = (CASE WHEN ('es-ES' IS  NULL) THEN (1)  ELSE (0) END)))) THEN (0) END AS `C1`, 
`Extent2`.`Name`, 
`Extent2`.`LanguageCode`
FROM `LinkTr` AS `Extent2`
 WHERE `Extent2`.`LinkId` = `Extent1`.`Id`) AS `Project1`
 ORDER BY 
`Project1`.`C1` DESC, 
`Project1`.`LanguageCode` ASC LIMIT 1) AS `C1`, 
(SELECT
`Project1`.`Name`
FROM (SELECT
CASE WHEN ((`Extent2`.`LanguageCode` = 'es-ES') OR ((`Extent2`.`LanguageCode` IS  NULL) AND ('es-ES' IS  NULL))) THEN (1)  WHEN (NOT ((`Extent2`.`LanguageCode` = 'es-ES') AND ((CASE WHEN (`Extent2`.`LanguageCode` IS  NULL) THEN (1)  ELSE (0) END) = (CASE WHEN ('es-ES' IS  NULL) THEN (1)  ELSE (0) END)))) THEN (0) END AS `C1`, 
`Extent2`.`Name`, 
`Extent2`.`LanguageCode`
FROM `LinkTr` AS `Extent2`
 WHERE `Extent2`.`LinkId` = `Extent1`.`Id`) AS `Project1`
 ORDER BY 
`Project1`.`C1` DESC, 
`Project1`.`LanguageCode` ASC LIMIT 1) AS `Name`, 
(SELECT
`Project1`.`LanguageCode`
FROM (SELECT
CASE WHEN ((`Extent2`.`LanguageCode` = 'es-ES') OR ((`Extent2`.`LanguageCode` IS  NULL) AND ('es-ES' IS  NULL))) THEN (1)  WHEN (NOT ((`Extent2`.`LanguageCode` = 'es-ES') AND ((CASE WHEN (`Extent2`.`LanguageCode` IS  NULL) THEN (1)  ELSE (0) END) = (CASE WHEN ('es-ES' IS  NULL) THEN (1)  ELSE (0) END)))) THEN (0) END AS `C1`, 
`Extent2`.`Name`, 
`Extent2`.`LanguageCode`
FROM `LinkTr` AS `Extent2`
 WHERE `Extent2`.`LinkId` = `Extent1`.`Id`) AS `Project1`
 ORDER BY 
`Project1`.`C1` DESC, 
`Project1`.`LanguageCode` ASC LIMIT 1) AS `LanguageCode`
   FROM `Link` AS `Extent1`) AS `Apply1`

编辑 3

实体是:

public class Link : EntityBase
{
    public int OrderPos { get; set; }
    public string Url { get; set; }
    public bool Active { get; set; }

    public virtual IEnumerable<LinkTr> Translations { get; set; }
}

public class LinkTr : EntityBaseTr
{
    public string Name { get; set; }
    public string Summary { get; set; }

    //[ForeignKey("Link")]
    public int LinkId { get; set; }
    public virtual Link Link { get; set; }

    //[ForeignKey("Language")]
    public string LanguageCode { get; set; }
    public virtual Language Languages { get; set; }
}

public class EntityBase
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] //[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int Id { get; set; }

    public DateTime? DateCreated { get; set; }
    public DateTime? DateModified { get; set; }
    public int UserIdModified { get; set; }
}

public class EntityBaseTr
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public DateTime? DateCreated { get; set; }
}

【问题讨论】:

  • "我需要帮助,因为如果当前语言存在,我需要返回当前语言,如果不是下一个。"因此,如果您没有找到匹配的翻译,您只需获取 any 其他语言代码的翻译?
  • 是的,第一个是当前的,如果它不存在,我会采取任何其他...如果我只是订购 LanguageCode 它可以工作,问题是当我试图强制当前的第一个
  • 我能找到的关于 Extent1.Id 的唯一问题是this one。但是你说它以前与 Id 一起工作......嗯......
  • 那不是我的情况....谢谢

标签: entity-framework linq sql-order-by


【解决方案1】:

不能与提供的信息重复。

我在测试期间唯一注意到的是表达式(translations == null) ? "" : translations.Name 正在生成null 检查Translations 表Id 列,不确定您的实体中是否有这样的。

无论如何,值得尝试以下不包括此类检查的替代方案:

var queryString = (
    from entity in _dbContext.Links
    let translationName = _dbContext.LinksTrs
        .Where(p => p.LinkId == entity.Id)
        .OrderBy(p => p.LanguageCode == currentLanguage ? 0 : 1)
        .Select(p => p.Name)
        .FirstOrDefault();
    select new LinksAdminListModel()
    {
        Id = entity.Id,
        Name = translationName ?? "",
        Url = entity.Url,
        Active = entity.Active
     });

更新:

事实证明这是当前的 MySql EF 查询提供程序问题(错误?!)。

玩了一段时间后,我唯一能让它工作的方法如下

var queryString =
    (from entity in db.Links
     let translations = 
        db.LinksTrs.Where(p => p.LinkId == entity.Id && p.LanguageCode == currentLanguage).FirstOrDefault() ??
        db.LinksTrs.Where(p => p.LinkId == entity.Id).OrderBy(p => p.LanguageCode).FirstOrDefault()
     select new LinksAdminListModel
     {
         Id = entity.Id,
         Name = (translations == null) ? "" : translations.Name,
         Url = entity.Url,
         Active = entity.Active
     });

【讨论】:

  • 同样的结果。不工作。我认为这与即使是简单的订单也不起作用的事实有关......(请参阅我的编辑)
  • 如果我在我的 ASP MVC EF 项目中运行您的解决方案,我得到:“方法 'Skip' 仅支持 LINQ to Entities 中的排序输入。必须在方法之前调用方法 'OrderBy' '跳过'。”但是,如果我在 SQL 客户端中运行生成的 SQL,我会收到相同的错误消息“'where 子句'中的未知列'Extent1.Id'”
  • 正如我所提到的,我已经在最新的 EF6 中尝试了您的查询和我的查询,它们的所有工作都没有任何问题。您使用的是什么实体框架版本?
  • 我使用的是 ASP.NET MVC EF6,数据库是 MySQL。我们正在使用 CodeFirst。问题是 Take(1) 与 Order 的结合...
  • 您的解决方案的结果相同...如果我删除 TAKE(1) 参数或 ORDERBY 它可以工作,但这不是我需要的...
猜你喜欢
  • 1970-01-01
  • 2011-08-10
  • 1970-01-01
  • 1970-01-01
  • 2021-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-27
相关资源
最近更新 更多