具有条件连接和非匿名的 LINQ 查询 return
LINQ Query with conditional join and non-anonymous return
我有一个针对 SQL 服务器数据库的 LINQ 查询,它将每一行的数据写入一个对象 Person
。在某些情况下,我想加入其他表并添加 Person
对象的更多字段,同时利用 LINQ 延迟加载。
Person
class 看起来像这样:
public class Person
{
// Data provided by Persons table
public string Name { get; set; }
public string CityName { get; set; }
public string JobName { get; set; }
// Data provided by Cities table
public int? CityPopulation
// Data provided by Jobs table
public int? AverageSalary
// Data from other tables
...
}
我试过使用三元运算符,但条件不是立即求值,而是发送到 SQL 服务器在那里求值,这样即使不需要也可以执行连接。
// Fill values provided by Person table
IQueryable<Person> query;
query = dbContext.Persons.Select(x => new Person
{
Name = x.Name,
CityName = x.CityName,
JobName = x.JobName,
// Get data from City table, perform join to Cities only when cityRequired
CityPopulation = cityRequired ? x.Cities.Population : (int?) null,
...
// Get data from Job table, perform join to Jobs only when jobsRequired
JobAverageSalary = jobRequired ? x.Jobs.AverageSalary : (int?) null,
...
// Get data from other tables
...
});
在 if 子句中编写连接语句并在每次连接后调用 Person
构造函数,但不是很高效和优雅:
IQueryable<Person> query;
query = dbContext.Persons.Select(x => new Person
{
Name = x.Name,
City = x.CityName,
Job = x.JobName,
}
if(cityRequired)
{
query = query.Join(dbContext.Cities, Person => Person.CityName, City => City.Name, (Person, City) => new Person
{
// Copying old values
Name = Person.Name,
CityName = Person.CityName,
JobName = Person.Jobname,
// Filling in new values from City
CityPopulation = City.Population,
}
}
if (jobRequired)
...
感谢任何帮助!
看看 LinqKit - AsExpandable + Predicate Builders + Sub-queries
我建议你留下你这样的人模型...
public class Person
{
// Data provided by Persons table
public string Name { get; set; }
public string CityName { get; set; }
public string JobName { get; set; }
}
然后使用来自其他表的可能的额外字段创建一个视图模型class。像这样将 Person 模型作为构造函数参数传递。
public class PersonViewModel
{
public PersonViewModel(Person person)
{
Name = person.Name;
CityName = person.CityName;
JobName = person.JobName;
}
public string Name { get; set; }
public string CityName { get; set; }
public string JobName { get; set; }
public int? CityPopulation { get; set; }
public int? AverageSalary { get; set; }
}
现在,运行 一个包含所有可能的依赖表的连接查询,然后使用结果像这样填充 PersonViewModel...
var query = dbContext.Persons
.Join(dbContext.Cities, person => person.CityName, city => city.Name,
(person, city) => new {person, city}).Join(dbContext.Jobs, person => person.person.JobName,
job => job.Name, (person, job) => new {person, job}).FirstOrDefault();
var personViewModel = new PersonViewModel(query.person.person)
{
// Get data from City table, perform join to Cities only when cityRequired
CityPopulation = cityRequired ? query.person.city.Population : (int?) null,
// Get data from Job table, perform join to Jobs only when jobsRequired
AverageSalary = jobRequired ? query.job.AverageSalary : (int?) null
};
return View(personViewModel);
希望对您有所帮助。
Ivan 在我的问题评论中发布的自定义扩展解决了这个问题。如果三元运算符中的条件计算结果为假,它会删除加入指令。
我有一个针对 SQL 服务器数据库的 LINQ 查询,它将每一行的数据写入一个对象 Person
。在某些情况下,我想加入其他表并添加 Person
对象的更多字段,同时利用 LINQ 延迟加载。
Person
class 看起来像这样:
public class Person
{
// Data provided by Persons table
public string Name { get; set; }
public string CityName { get; set; }
public string JobName { get; set; }
// Data provided by Cities table
public int? CityPopulation
// Data provided by Jobs table
public int? AverageSalary
// Data from other tables
...
}
我试过使用三元运算符,但条件不是立即求值,而是发送到 SQL 服务器在那里求值,这样即使不需要也可以执行连接。
// Fill values provided by Person table
IQueryable<Person> query;
query = dbContext.Persons.Select(x => new Person
{
Name = x.Name,
CityName = x.CityName,
JobName = x.JobName,
// Get data from City table, perform join to Cities only when cityRequired
CityPopulation = cityRequired ? x.Cities.Population : (int?) null,
...
// Get data from Job table, perform join to Jobs only when jobsRequired
JobAverageSalary = jobRequired ? x.Jobs.AverageSalary : (int?) null,
...
// Get data from other tables
...
});
在 if 子句中编写连接语句并在每次连接后调用 Person
构造函数,但不是很高效和优雅:
IQueryable<Person> query;
query = dbContext.Persons.Select(x => new Person
{
Name = x.Name,
City = x.CityName,
Job = x.JobName,
}
if(cityRequired)
{
query = query.Join(dbContext.Cities, Person => Person.CityName, City => City.Name, (Person, City) => new Person
{
// Copying old values
Name = Person.Name,
CityName = Person.CityName,
JobName = Person.Jobname,
// Filling in new values from City
CityPopulation = City.Population,
}
}
if (jobRequired)
...
感谢任何帮助!
看看 LinqKit - AsExpandable + Predicate Builders + Sub-queries
我建议你留下你这样的人模型...
public class Person
{
// Data provided by Persons table
public string Name { get; set; }
public string CityName { get; set; }
public string JobName { get; set; }
}
然后使用来自其他表的可能的额外字段创建一个视图模型class。像这样将 Person 模型作为构造函数参数传递。
public class PersonViewModel
{
public PersonViewModel(Person person)
{
Name = person.Name;
CityName = person.CityName;
JobName = person.JobName;
}
public string Name { get; set; }
public string CityName { get; set; }
public string JobName { get; set; }
public int? CityPopulation { get; set; }
public int? AverageSalary { get; set; }
}
现在,运行 一个包含所有可能的依赖表的连接查询,然后使用结果像这样填充 PersonViewModel...
var query = dbContext.Persons
.Join(dbContext.Cities, person => person.CityName, city => city.Name,
(person, city) => new {person, city}).Join(dbContext.Jobs, person => person.person.JobName,
job => job.Name, (person, job) => new {person, job}).FirstOrDefault();
var personViewModel = new PersonViewModel(query.person.person)
{
// Get data from City table, perform join to Cities only when cityRequired
CityPopulation = cityRequired ? query.person.city.Population : (int?) null,
// Get data from Job table, perform join to Jobs only when jobsRequired
AverageSalary = jobRequired ? query.job.AverageSalary : (int?) null
};
return View(personViewModel);
希望对您有所帮助。
Ivan 在我的问题评论中发布的自定义扩展解决了这个问题。如果三元运算符中的条件计算结果为假,它会删除加入指令。