具有条件连接和非匿名返回的LINQ查询

时间:2018-01-14 11:02:35

标签: c# linq join linq-to-sql

我对SQL Server数据库进行了LINQ查询,该数据库将每行的数据写入对象Person。在某些情况下,我想加入其他表并添加Person个对象的更多字段,同时利用LINQs延迟加载。

Person类看起来像这样:

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 Server进行评估,以便即使不需要也可以执行连接。

// 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子句中编写join语句并在每次连接后调用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)
...

我感谢任何帮助!

3 个答案:

答案 0 :(得分:1)

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

public class Person
{
    // Data provided by Persons table
    public string Name { get; set; }
    public string CityName { get; set; }
    public string JobName { get; set; }
}

然后使用其他表中可能的额外字段创建一个视图模型类。将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);

我希望这会有所帮助。

答案 1 :(得分:0)

看看LinqKit - AsExpandable + Predicate Builders +子查询

LinqKit on GitHub

LinqKit on Nuget

答案 2 :(得分:0)

我的问题评论中发布的自定义扩展Ivan解决了这个问题。如果三元运算符中的条件求值为false,则删除要加入的指令。