Tengo una consulta LINQ contra una base de datos de SQL Server que escribe los datos de cada fila en un objeto Person
. Bajo ciertas condiciones, deseo unirme con tablas adicionales y agregar algunos campos más de los objetos Person
, todo mientras aprovecho la carga diferida de LINQ.
La clase Person
tiene este aspecto:
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
...
}
Intenté usar el operador ternario, pero la condición no se evalúa de inmediato, sino que se envía a SQL Server para ser evaluada allí, de modo que la unión se ejecute incluso si no es necesaria.
// 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
...
});
Escribir las declaraciones de unión en una cláusula if y llamar al constructor Person
después de que cada unión funcione, pero no es muy eficiente y elegante:
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)
...
Agradezco cualquier ayuda!
3 respuestas
La extensión personalizada que Ivan publicó en el comentario a mi pregunta resolvió el problema. Elimina la instrucción para unirse si la condición en el operador ternario se evalúa como falsa.
Eche un vistazo a LinqKit - AsExpandable + Predicate Builders + Sub-consultas
Te sugiero que te dejes como modelo de persona así ...
public class Person
{
// Data provided by Persons table
public string Name { get; set; }
public string CityName { get; set; }
public string JobName { get; set; }
}
Luego, cree una clase de modelo de vista con el posible campo adicional de otras tablas. Pasar el modelo Person como un parámetro constructor como este.
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; }
}
Ahora, ejecute una consulta de combinación que incluya todas las tablas dependientes posibles y luego use el resultado para llenar el PersonViewModel de esta manera ...
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);
Espero que esto ayude.
Nuevas preguntas
c#
C # (pronunciado "see sharp") es un lenguaje de programación multi-paradigma de alto nivel, estáticamente tipado desarrollado por Microsoft. El código C # generalmente se dirige a la familia de herramientas y tiempos de ejecución .NET de Microsoft, que incluyen .NET Framework, .NET Core y Xamarin, entre otros. Use esta etiqueta para preguntas sobre el código escrito en las especificaciones formales de C # o C #.