C# 如何将这些类似的linq查询组合成一个查询?
这可能是一个基本的LINQ问题。我需要选择一个对象,如果为空,则选择另一个。我正在以以下方式使用linq to对象,我知道这可以更快、更好、更干净地完成C# 如何将这些类似的linq查询组合成一个查询?,c#,linq,C#,Linq,这可能是一个基本的LINQ问题。我需要选择一个对象,如果为空,则选择另一个。我正在以以下方式使用linq to对象,我知道这可以更快、更好、更干净地完成 public Attrib DetermineAttribution(Data data) { var one = from c in data.actions where c.actionType == Action.ActionTypeOne
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();
}
这两个linq操作只在where子句上有所不同,我知道有一种方法可以将它们结合起来。如有任何想法,将不胜感激
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();
但这并不保证ActionTypeOne会在ActionTypeTwo之前找到。它查找第一条记录,即ActionTypeOne或ActionTypeTwo
但这并不保证ActionTypeOne会在ActionTypeTwo之前找到。它查找第一条记录,即ActionTypeOne或ActionTypeTwo。这不使用查询语法,但它保留了以下逻辑:类型为
ActionTypeOne
的元素在ActionTypeTwo
的元素之前返回。由于延迟计算,除非没有类型为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();
}
这不使用查询语法,但它保留了
ActionTypeOne
类型的元素在ActionTypeTwo
元素之前返回的逻辑。由于延迟计算,除非没有类型为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();
}
我建议:
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 types=Enum.GetValues(typeof(Action)).Cast();
var merged=来自data.actions中的c
从t型开始
其中c.actionType==t
选择新属性{id=c.id,name=c.name};
返回merged.FirstOrDefault();
}
我建议:
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 types=Enum.GetValues(typeof(Action)).Cast();
var merged=来自data.actions中的c
从t型开始
其中c.actionType==t
选择新属性{id=c.id,name=c.name};
返回merged.FirstOrDefault();
}
等效的SQL查询是(我使用了Case语句,因为我不知道ActionType列的数据类型):
等效的SQL查询是(我使用了Case语句,因为我不知道ActionType列的数据类型):
我认为这个解决方案简单有效:
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;
}
我认为这个解决方案简单有效:
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;
}
您可以使用orderby来确保项目的检索顺序。@codymanix:您必须指定一个自定义比较器,以便在
ActionTypeOne
类型的元素之前返回ActionTypeTwo
类型的元素(不能保证默认情况下它们会按这种方式排序)。它还需要一些可以在线性时间内运行的东西,并将其转换为n个log(n)。99%的时间都不重要,但需要注意的是。您可以使用orderby来确保检索项目的顺序。@codymanix:您必须指定一个自定义比较器,以便在返回ActionTypeOne
类型的元素之前返回ActionTypeTwo
(不能保证默认情况下它们会按这种方式排序)。它还需要一些可以在线性时间内运行的内容,并将其转换为n个日志(n)。99%的时间都不重要,但需要注意一些内容。您应该使用.Any()而不是.Count().Count()遍历整个序列,而Any只检查第一个项是否存在。@MikeD:应该注意的是,上面的内容没有编译,因为如果两个序列都没有您要查找的项,则不会返回值。对不起,我试图在SO窗口中将我的方法清理为简洁的内容,显然是tooke太多了。您应该使用.Any()而不是.Count().Count()遍历整个序列,而Any只检查第一个项是否存在。@MikeD:应该注意的是,上面的内容没有编译,因为如果两个序列都没有您要查找的项,则不会返回值。对不起,我试图在SO窗口中将我的方法清理为简洁的内容,显然是tooke太多了。