实体框架查询以逗号分隔的字段

use*_*107 1 c# sql-server asp.net-mvc entity-framework

我有一个名为Article的表:

-Id
-Title
-Content
-Tags (This is a comma seperated list of tags e.g. 'Sports,Italy,Ferrari')
Run Code Online (Sandbox Code Playgroud)

使用实体框架我希望能够找到所有具有特定标签的文章.

List<Article> GetArticles(List<String> tags)
{
  //do an entity framework query here to find all articles which have the tags specified
} 
Run Code Online (Sandbox Code Playgroud)

返回的条目应包含指定的所有标记.例如,如果函数的输入是'car','blue',则应返回具有这些至少这2个标记的所有条目.

我无法想象我将如何实现这一点.我知道如何使用存储过程实现这一点,这是我的计划b.

Chr*_*att 5

存储过程实际上是一个很好的选择,如果不是最好的选择,真的.但是,您仍然可以通过Contains以下方式实现:

var articles = db.Articles.Where(m => tags.Any(t => m.Tags.Contains(t)));
Run Code Online (Sandbox Code Playgroud)

这样做基本上是遍历传入的标签,并创建一个查询是否Tags与任何一个相似的查询.请记住,因为这将是一个LIKE查询,它将是sloooooowwwww,除非您的Tags列被索引,这也需要是一个定义的长度,而不是像NVARCHAR(MAX).

另一个潜在的问题是假匹配.假设您有标签"Read"和"Reading",因为这是一个LIKE查询,搜索"Read"标签将返回两者.实际上,解决这个问题的唯一方法是在数据中添加标记分隔符,例如:"[Read],[Reading]".然后,您搜索而不是"[Read]",而不是"Read",并且您保证只撤回正确的.

当我需要打包/解压这样的字符串时,我通常会做类似的事情:

public string Tags
{
    get
    {
        return TagsList != null
            ? String.Join(",", TagsList.Select(tag => "[" + tag + "]"))
            : null;
    }
    set
    {
        TagsList = !String.IsNullOrWhiteSpace(value)
            ? value.Replace("[", "").Replace("]", "").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList()
            : new List<string>();
    }
}

[NotMapped]
public List<string> TagsList { get; set; }
Run Code Online (Sandbox Code Playgroud)

这看起来相当复杂,但所有这一切都在于setter正在解析分隔符上的标记列表,删除我选择使用的短语分隔字符,[以及].getter将列表打包回一个包含所有内容的字符串.

这允许您随后使用TagsList,字符串版本将自动保留,而不必考虑它.但是,在查询时,您仍然需要查询Tags,因为这是实际的数据库支持的属性.

  • 好吧,你总是可以自己制作你的标签第一类对象,这样你实际上就有了一个`Tags`表,然后是那个和`Article`之间的M2M关系.这消除了几乎所有的麻烦,使查询变得非常简单和快速.但是,如果您需要将其保留为字符串,那么不,这是您唯一的选择. (3认同)