C# 将逻辑从lambda表达式拆分为多个LINQ表达式
下面的代码示例说明了我的问题。 我如何将lambda的一部分放置在其他地方 如何从“GetGurus()”方法调用“Foo”? 我希望LINQ将其转换为1语句C# 将逻辑从lambda表达式拆分为多个LINQ表达式,c#,linq,lambda,linq-to-entities,C#,Linq,Lambda,Linq To Entities,下面的代码示例说明了我的问题。 我如何将lambda的一部分放置在其他地方 如何从“GetGurus()”方法调用“Foo”? 我希望LINQ将其转换为1语句 public enum GuruLevel { NotSet, Goku, SuperSayan } private IEnumerable<PersonInfo> GetGurus() { using (var context = new CRMContext()) {
public enum GuruLevel
{
NotSet,
Goku,
SuperSayan
}
private IEnumerable<PersonInfo> GetGurus()
{
using (var context = new CRMContext())
{
var persons = context.Person
.Where(p => p.Experience > 10)
.OrderBy(p => p.DateOfBirth)
.Select(p => new PersonInfo())
{
StackOverFlowName = p.StackOverFlowName,
Experience = p.Experience,
GuruStatus = Foo //(p.Experience > 9000) ? GuruLevel.SuperSayan : GuruLevel.Goku
}
return persons.ToList();
}
}
public static System.Linq.Expressions.Expression<Func<Person, GuruLevel>> Foo
{
get
{
return bar => (bar.Experience > 9000) ? GuruLevel.SuperSayan : GuruLevel.Goku;
}
}
public enum GuruLevel
{
未设置,
小悟空,
超级萨扬
}
私有IEnumerable GetGurus()
{
使用(var context=new CRMContext())
{
var persons=context.Person
.其中(p=>p.经验>10)
.OrderBy(p=>p.DateOfBirth)
.Select(p=>newpersoninfo())
{
StackOverFlowName=p.StackOverFlowName,
经验,经验,
GuruStatus=Foo/(p.Experience>9000)?GuruLevel.SuperSayan:GuruLevel.Goku
}
返回人员。ToList();
}
}
public static System.Linq.Expressions.Expression Foo
{
得到
{
返回条=>(bar.Experience>9000)?GuruLevel.SuperSayan:GuruLevel.Goku;
}
}
更改此项
public static Func<Person, GuruLevel> Foo
{
get
{
return bar => (bar.Experience > 9000) ? GuruLevel.SuperSayan : GuruLevel.Goku;
}
}
改变这一点
public static Func<Person, GuruLevel> Foo
{
get
{
return bar => (bar.Experience > 9000) ? GuruLevel.SuperSayan : GuruLevel.Goku;
}
}
此逻辑由
PersonInfo
类负责。此代码通常放在构造函数或工厂类中,并且完全符合单一责任原则
class PersonInfo
{
public string StackOverFlowName { get; set; }
public int Experience { get; set; }
public GuruLevel GuruStatus { get; set; }
public void PersonInfo(Person p)
{
StackOverFlowName = p.StackOverFlowName;
Experience = p.Experience;
GuruStatus = p.Experience > 9000 ? GuruLevel.SuperSayan : GuruLevel.Goku;
}
}
然后将您的服务方法更改为:
private IEnumerable<PersonInfo> GetGurus()
{
using (var context = new CRMContext())
{
var persons = context.Person
.Where(p => p.Experience > 10)
.OrderBy(p => p.DateOfBirth)
.ToList()
.Select(p => new PersonInfo(p))
return persons.ToList();
}
}
此逻辑由
PersonInfo
类负责。此代码通常放在构造函数或工厂类中,并且完全符合单一责任原则
class PersonInfo
{
public string StackOverFlowName { get; set; }
public int Experience { get; set; }
public GuruLevel GuruStatus { get; set; }
public void PersonInfo(Person p)
{
StackOverFlowName = p.StackOverFlowName;
Experience = p.Experience;
GuruStatus = p.Experience > 9000 ? GuruLevel.SuperSayan : GuruLevel.Goku;
}
}
然后将您的服务方法更改为:
private IEnumerable<PersonInfo> GetGurus()
{
using (var context = new CRMContext())
{
var persons = context.Person
.Where(p => p.Experience > 10)
.OrderBy(p => p.DateOfBirth)
.ToList()
.Select(p => new PersonInfo(p))
return persons.ToList();
}
}
这不是你问题的直接答案,但它与你问的原因有关 我假设,您使用的是某种数据库,所以您不能使用常规方法,因为它们不会被数据库的上下文所知道 例如,您实际上可以执行私有方法来处理数据,但不能使用自定义类型或类。在您的示例中,“GuruLevel”不会被DB识别 我建议不要尝试在DB端进行转换。取而代之的是以DB格式检索所有需要的数据,并在应用程序端进行转换
using (var context = new CRMContext())
{
var persons = context.Person
.Where(p => p.Experience > 10)
.OrderBy(p => p.DateOfBirth)
.Select(p => new {p.StackOverFlowName, p.Experience }) //or whole object, or other fields if needed
.ToList() //executes query, all following code will be in a context of application not DB
.Select(p => new PersonInfo())
{
StackOverFlowName = p.StackOverFlowName,
Experience = p.Experience,
GuruStatus = GetGuruStatus(p.Experience)
}
return persons.ToList();
}
private GuruLevel GetGuruLevel(int exp)
{
return exp > 9000 ? GuruLevel.SuperSayan : GuruLevel.Goku
}
这不是你问题的直接答案,但它与你问的原因有关 我假设,您使用的是某种数据库,所以您不能使用常规方法,因为它们不会被数据库的上下文所知道 例如,您实际上可以执行私有方法来处理数据,但不能使用自定义类型或类。在您的示例中,“GuruLevel”不会被DB识别 我建议不要尝试在DB端进行转换。取而代之的是以DB格式检索所有需要的数据,并在应用程序端进行转换
using (var context = new CRMContext())
{
var persons = context.Person
.Where(p => p.Experience > 10)
.OrderBy(p => p.DateOfBirth)
.Select(p => new {p.StackOverFlowName, p.Experience }) //or whole object, or other fields if needed
.ToList() //executes query, all following code will be in a context of application not DB
.Select(p => new PersonInfo())
{
StackOverFlowName = p.StackOverFlowName,
Experience = p.Experience,
GuruStatus = GetGuruStatus(p.Experience)
}
return persons.ToList();
}
private GuruLevel GetGuruLevel(int exp)
{
return exp > 9000 ? GuruLevel.SuperSayan : GuruLevel.Goku
}
感谢您的尝试,但这会导致:“LINQ to实体中不支持LINQ表达式节点类型‘Invoke’。@Tony_Kilopamikegolf如果答案适用于LINQ to对象;你没有说明你是在没有注意的情况下工作的。我不知道是EF。也许我的编辑会工作,因为它是一个标准的功能。不确定。我不使用EFQ谢谢您的尝试,但这会导致:“LINQ to实体中不支持LINQ表达式节点类型‘Invoke’。@Tony_Kilopamikegolf答案在LINQ to对象中有效;你没有说明你是在没有注意的情况下工作的。我不知道是EF。也许我的编辑会工作,因为它是一个标准的功能。不确定。我不使用EFIf
CrmContext
是EF6,这将在查询转换期间在运行时崩溃。不支持带参数的构造函数。我喜欢它,但问题是关于拆分lambda的。仍然+1@Impworks没错,他可能会在初始化之前执行此查询。@bixarrio我试图避免生成更多代码气味样本的答案。如果作者知道Expression
类,我假设他能够将这个属性转换成一个方法。在现实世界中,“GuruLevel”是在PersonInfo中没有的、但可以亲自使用的更多字段上计算的。如果CrmContext
是EF6,则在查询转换过程中,这将在运行时崩溃。不支持带参数的构造函数。我喜欢它,但问题是关于拆分lambda的。仍然+1@Impworks没错,他可能会在初始化之前执行此查询。@bixarrio我试图避免生成更多代码气味样本的答案。如果作者知道Expression
类,我假设他能够将这个属性转换成一个方法。在现实世界中,“GuruLevel”是根据更多的字段计算的,这些字段在PersonInfo中不可用,但可以亲自使用。我正在阅读您的链接,似乎这正是我需要的。尽管实施起来似乎相当复杂:(遗憾的是,你没有发布答案,因为你给出了最好的答案!我安装了。它很有效!事实上,这个问题与我提到的问题是重复的。理想情况下,它应该因此而关闭。我们的最终用户现在也非常高兴!我们项目查询的性能提升超出了预期!我很喜欢it!我正在阅读您的链接,似乎这正是我所需要的。尽管实现起来似乎相当复杂:(遗憾的是,你没有发布答案,因为你给出了最好的答案!我安装了。它很有效!事实上,这个问题与我提到的问题是重复的。理想情况下,它应该因此而关闭。我们的最终用户现在也非常高兴!我们项目查询的性能提升超出了预期!我很喜欢信息技术