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
精彩评论