LINQ to Entities: Why can't I use Split method as condition?

半世苍凉 提交于 2019-11-29 15:03:40

In response to your performance considerations on a big dataset:

You are going to be doing non indexed wildcard string matching on the client, so yes, there will be performance loss.

Is there a reason why you have multiple keywords in one table field? You could normalize that out, to have a ActivityKeywords table where for each Activity you have a number of Keyword records.

Activities(activity_id, ... /* remove keywords field */) ---> ActivityKeywords(activity_id, keyword_id) ---> Keywords(keyword_id, value)

Check out Non-first normal form: http://en.wikipedia.org/wiki/Database_normalization

EDIT: Also even if you were to stick with the one column, there is a way to do everything serverside (if you have a strict syntax: 'keyword1, keyword2, ..., keywordN'):

var aKeyword = "ACT";
var results = (from a in db.Activities
              where a.Keywords.Contains("," + aKeyword) || a.Keywords.Contains(aKeyword + ",")
              select a;

Your problem is that LINQ-to-Entites has to translate everything you give it into SQL to send to the database.

If that is really what you need to do, you'll have to force LINQ-to-Entities to pull back all the data and LINQ-to-Objects to evaluate the condition.

Ex:

var aKeyword = "ACT";
var results = from a in db.Activities.ToList()
              where a.Keywords.Split(',').Contains(aKeyword) == true
              select a;

Be aware though, that this will pull back all the objects from the Activities table. An alternative may be to let the DB do a bit of an initial filter, and filter down the rest of the way afterwards:

var aKeyword = "ACT";
var results = (from a in db.Activities
              where a.Keywords.Contains(aKeyword)
              select a).ToList().Where(a => a.KeyWords.Split(',').Contains(aKeyword));

That will let LINQ-to-Entities do the filter it understands (string.Contains becomes a like query) that will filter down some of the data, then apply the real filter you want via LINQ-to-Objects once you have the objects back. The ToList() call forces LINQ-to-Entities to run the query and build the objects, allowing LINQ-to-Objects to be the engine that does the second part of the query.

My guess is the way you are calling Split. It should take an array. Maybe there is another Split in Linq it is finding and giving you an unusual error:

This works for Linq to Objects:

 var dataStore = new List<string>
                    {
                        "foo,bar,zoo",
                        "yelp,foo",
                        "fred",
                        ""
                    };
 var results = from a in dataStore
               where a.Split(new[] {','}).Contains("foo")
               select a;

 foreach (var result in results)
 {
     Console.WriteLine("Match: {0}", result);
 }

Outputs the following:

Match: foo,bar,zoo
Match: yelp,foo

Actually, thinking about it, do you need the split at all? a.Contains("foo") may be enough for you (unless you don't want to hit foobar).

Marc

You may want to look at this question about L2E and .Contains for a solution that should be more efficient than guessing at a superset before filtering client side.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!