【问题标题】:Entity framework and linq string comparsion issue实体框架和linq字符串比较问题
【发布时间】:2013-11-05 08:24:13
【问题描述】:

linq.. 有问题。

让我们看看代码

我有一个文章类:

public calss Article
{
    public string Tag{get; set; }
}

我保存文章的每个标签,以, 逗号分隔。

例如:first,second,third

当我想获得一篇文章时,我想获得具有任何共同标签的文章。

我使用这个查询但是:

var relatedArticles = 
        _db.Articles.Where(a => a.Tag
                                 .Split('،')
                                 .Any(t => article.Tag
                                                  .Split('،')
                                                  .Any(ac => ac == t)));

我得到了这个例外:

LINQ to Entities 无法识别方法“System.String[] Split(Char[])' 方法

还有其他方法吗?

更新: 我不能将标签保留在不同的表格中,因为我必须让用户在插入文章时创建任意数量的标签。 像 50 并且在将文章保存到数据库时检查该标签是否存在将是开销。

【问题讨论】:

  • 如果你可以有多个标签,为什么不将它们保存在列表、数组或任何其他类型的容器中,而不是使用字符串操作?
  • 你能给我看一个带有查询的示例代码吗?
  • 那不是好的桌子设计。您需要将表格规范化为第三种形式,因为这看起来像 n:m 参考。将文章保存在一个引用映射表的表中,在该表中引用arcticleId 和tagid,而不是一个带有主键tagid 的标签的表。比你只需要编辑例如标签表中的一个标签,如果它发生变化,它将在每个参考arcticle 更新。编辑:我刚刚认识到你不是在谈论表格,无论如何你标记为 sql-server。看看nvoigt的答案,和我提到的一样,但不是table design

标签: c# sql-server linq entity-framework tsql


【解决方案1】:

如下设置你的类:

public class Article
{
    public List<string> Tag{get; set; }
}

我不能 100% 确定您的第二条语句是做什么的,但您可以使用 a.Tag.Contains() 来检查您的值。

【讨论】:

    【解决方案2】:

    我认为我的评论可以作为对您问题的答案,所以我把它写下来:)

    您应该考虑一下您的表/类设计。

    您需要对其进行规范化,因为它看起来像 n:m 引用。将文章保存在一个引用映射表的表中,在该表中引用 arcticleId 和 tagId,而不是一个带有主键 tagId 的标签的表。 如果将来某个标签发生变化,您无需更新每篇文章,只需更新该特定标签,每篇文章都会更改。

    【讨论】:

      【解决方案3】:

      “a.Tag.Split('،')”是您的 IQueryable 所在的表达式树中的一个节点,而不是实际操作。当您通过调用 ToList 之类的方法实现结果时,整个表达式树在执行之前会被转换为 SQL 表达式 - 这是错误点,因为翻译器不知道如何将 Split() 方法转换为 sql 语句。
      作为替代方案,您可以将所有结果检索到应用程序中,通过 ToList() 实现它们,然后将它们作为 IEnumerables 执行您想要的操作。此外,您可以编写一个存储过程并将搜索标签数组传递到那里。
      此外,也许它会起作用 - 尝试将一个简单的值数组(不是作为方法)传递到查询中,以便生成的 sql 看起来像

      "WHERE ... IN ...".
      

      【讨论】:

        【解决方案4】:

        这意味着 Linq to entity 找不到可以写为 SQL 查询的拆分方法的翻译。如果您想执行拆分功能,您必须通过调用ToList()AsEnumerable() 等将记录带入内存。

        但更好的方法是为您的数据库中的标签创建单独的表。

        Linq 查询看起来像这样(假设文章和标签之间存在多对多关系):

        var relatedArticles = 
                _db.Articles.Where(a => a.Tags.Any(t => t.Articles.Count() > 1));
        // if Article has Tag which is assigned more then to one Article then it suits us
        

        【讨论】:

        • 但必须记住,如果要查询任何大表,将通过调用 ToList() 将全部数据量读取到内存中。这可能效果不佳。
        • 谢谢@Dom84,更好的方法是规范化数据库以更好地适应标签
        【解决方案5】:

        在使用 EF 时,您不能直接在 Linq 中调用像 string.Split() 这样的常规方法,因为它无法转换为 SQL。

        您可以将AsEnumerable() 附加到您的Where() 子句中,以使Linq 获取数据,从而允许您稍后对其执行类似的操作。不幸的是,这将不允许您在不获取整个列表的情况下对列表执行您想要的操作,我相信您宁愿避免这样做。

        也许你可以这样做?:

         List<string> tagsForCurrentArticle = ... // fetch this first somehow
        
         _db.Articles.Where(a =>  
                              tagsForCurrentArticle.Any(tag => 
                                                           a.Tag.Contains(tag)))
        

        请注意,要明确一点:这应该可行,但如果可能的话,更好的选择是将标签移到单独的表格中,正如其他人所建议的那样。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-06-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-24
          • 1970-01-01
          相关资源
          最近更新 更多