具有条件连接和非匿名的 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

LinqKit on GitHub

LinqKit on Nuget

我建议你留下你这样的人模型...

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 在我的问题评论中发布的自定义扩展解决了这个问题。如果三元运算符中的条件计算结果为假,它会删除加入指令。