开发者

How do I combine these similar linq queries into one?

This is probably a basic LINQ question. I have need to select one object and if it is null select another. I'm using linq to objects in the following way, that 开发者_如何学JAVAI know can be done quicker, better, cleaner...

    public Attrib DetermineAttribution(Data data)
    {

        var one = from c in data.actions
                           where c.actionType == Action.ActionTypeOne
                           select new Attrib 
                                      {
                                          id = c.id,
                                          name = c.name
                                      };
        if( one.Count() > 0)
            return one.First();

        var two = from c in data.actions
                  where c.actionType == Action.ActionTypeTwo
                  select new Attrib
                             {
                                 id = c.id,
                                 name = c.name
                             };
        if (two.Count() > 0 )
            return two.First();

  }

The two linq operations differ only on the where clause and I know there is a way to combine them. Any thoughts would be appreciated.


I think this solution is simple and efficient:

public Attrib DetermineAttribution(Data data)
{
    var c = data.actions.FirstOrDefault(c => c.actionType == Action.ActionTypeOne) ??
            data.actions.FirstOrDefault(c => c.actionType == Action.ActionTypeTwo);
    return c != null ? new Attrib { id = c.id, name = c.name } : null;
}


This doesn't use the query syntax, but it preserves the logic that an element of type ActionTypeOne is return before an element of ActionTypeTwo. And because of lazy evaluation, the second query won't be executed unless there are no elements of type ActionTypeOne.

public Attrib DetermineAttribution(Data data)
{

    return data.actions.Where( c => c.actionType == Action.ActionTypeOne)
              .Concat( data.actions.Where( c.actionType == Action.ActionTypeTwo ) )
              .Select( c => new Attrib
                         {
                             id = c.id,
                             name = c.name
                         })
              .FirstOrDefault();
}


 var one = (from c in data.actions
                           where (c.actionType == Action.ActionTypeOne) || (c.actionType == Action.ActionTypeTwo)
                           select new Attrib 
                                      {
                                          id = c.id,
                                          name = c.name
                                      }).FirstOrDefault();

This does not guarantee that ActionTypeOne will be found before ActionTypeTwo though. It finds the first record that is ActionTypeOne or ActionTypeTwo.


I would suggest:

 public Attrib DetermineAttribution(Data data)
 {
        var types = Enum.GetValues(typeof (Action)).Cast<Action>();
        var merged = from c in data.actions
                     from t in types
                     where c.actionType == t
                     select new Attrib {id = c.id, name = c.name};

        return merged.FirstOrDefault();
 }


 var one =  from c in data.actions
                where c.actionType == Action.ActionTypeOne
                    || c.actionType == Action.ActionTypeTwo
                orderby c.actionType == Action.ActionTypeOne ? 0 : 1
                select new Attrib 
                                {
                                  id = c.id,
                                  name = c.name
                                }).FirstOrDefault();

The equivalent SQL query would be ( I used a Case statement because I did not know the data type of the ActionType column):

Select TOP 1 id, name
From Actions
where ActionType In(ActionTypeOne, ActionTypeTwo)
Order By Case ActionType When 1 Then 0 Else 1 End ASC
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜