Cómo hacer uniones en LINQ en múltiples campos en una sola unión


Necesito hacer una consulta LINQ2DataSet que haga una combinación en más de un campo (como

var result = from x in entity
join y in entity2 
       on x.field1 = y.field1 
and 
          x.field2 = y.field2

Todavía he encontrado una solución adecuada (puedo agregar las restricciones adicionales a una cláusula where, pero esto está lejos de ser una solución adecuada, o usar esta solución, pero que asume un equijoin).

¿Es posible en LINQ unir varios campos en una sola combinación?

EDITAR

var result = from x in entity
             join y in entity2
             on new { x.field1, x.field2 } equals new { y.field1, y.field2 }

Es la solución a la que me referí como asumiendo un equijoin arriba.

Además EDITAR

Para responder a la crítica de que mi ejemplo original era un equijoin, reconozco que, Mi requisito actual es para un equijoin y ya he empleado la solución que mencioné anteriormente.

Estoy, sin embargo, tratando de entender qué posibilidades y mejores prácticas tengo / debo emplear con LINQ. Voy a necesitar hacer una consulta de rango de fechas unirse con un ID de tabla pronto, y estaba anticipando ese problema, parece que tendré que agregue el rango de fechas en la cláusula where.

Gracias, como siempre, por todas las sugerencias y comentarios dados

 205
Author: Community, 2008-12-17

12 answers

La solución con el tipo anónimo debería funcionar bien. LINQ puede solo representar equijoins (con cláusulas join, de todos modos), y de hecho eso es lo que has dicho que quieres expresar de todos modos basado en tu consulta original.

Si no le gusta la versión con el tipo anónimo por alguna razón específica, debe explicar esa razón.

Si quieres hacer algo que no sea lo que originalmente pediste, por favor da un ejemplo de lo que realmente quieres hacer hacer.

EDITAR: Respondiendo a la edición en la pregunta: sí, para hacer una unión de "intervalo de fechas", necesita usar una cláusula where en su lugar. Son semánticamente equivalentes realmente, por lo que es sólo una cuestión de las optimizaciones disponibles. Las Equijoins proporcionan una optimización simple (en LINQ to Objects, que incluye LINQ to DataSets) mediante la creación de una búsqueda basada en la secuencia interna, piense en ella como una tabla hash de clave a una secuencia de entradas que coincidan con esa clave.

Hacer eso con intervalos de fechas es algo más difícil. Sin embargo, dependiendo exactamente de lo que quieres decir con un "rango de fechas unirse" usted puede ser capaz de hacer algo similar - si usted está planeando en la creación de "bandas" de fechas (por ejemplo, una por año) de modo que dos entradas que se producen en el mismo año (pero no en la misma fecha) deben coincidir, entonces usted puede hacerlo simplemente mediante el uso de esa banda como la clave. Si es más complicado, por ejemplo, un lado de la unión proporciona un rango, y el otro lado de la unión proporciona una sola fecha, coincidiendo si cae dentro de ese rango, sería mejor manejarlo con una cláusula where (después de una segunda cláusula from) OMI. Podrías hacer algo de magia particularmente funky ordenando un lado u otro para encontrar partidos de manera más eficiente, pero eso sería mucho trabajo, solo haría ese tipo de cosas después de verificar si el rendimiento es un problema.

 77
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-17 09:09:49
var result = from x in entity
   join y in entity2 on new { x.field1, x.field2 } equals new { y.field1, y.field2 }
 106
Author: KristoferA,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-17 03:57:50
var result = from x in entity1
             join y in entity2
             on new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 }

Debe hacer esto, si los nombres de columna son diferentes en dos entidades.

 57
Author: RealNapster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-13 22:01:55

Solo para completar esto con una sintaxis de cadena de método equivalente:

entity.Join(entity2, x => new {x.Field1, x.Field2},
                     y => new {y.Field1, y.Field2}, (x, y) => x);

Mientras que el último argumento (x, y) => x es lo que usted selecciona (en el caso anterior seleccionamos x).

 45
Author: niieani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-04 15:53:04

Creo que una opción más legible y flexible es usar la función Where:

var result = from x in entity1
             from y in entity2
                 .Where(y => y.field1 == x.field1 && y.field2 == x.field2)

Esto también permite cambiar fácilmente de unión interna a unión izquierda añadiendo .DefaultIfEmpty ().

 24
Author: Alexei,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-09 10:30:34
var result = from x in entity
             join y in entity2
             on new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 }
             select new 
             {
               /// Columns
              };
 9
Author: user3966657,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-22 05:14:42

Usando el operador join solo se pueden realizar equijoins. Otros tipos de uniones se pueden construir usando otros operadores. No estoy seguro de si la unión exacta que está tratando de hacer sería más fácil usando estos métodos o cambiando la cláusula where. La documentación sobre la cláusula join se puede encontrar aquí. MSDN tiene un artículo sobre operaciones de unión con múltiples enlaces a ejemplos de otras uniones, también.

 7
Author: tvanfosson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-17 03:58:41

Podrías hacer algo como (abajo)

var query = from p in context.T1

        join q in context.T2

        on

        new { p.Col1, p.Col2 }

        equals

         new { q.Col1, q.Col2 }

        select new {p...., q......};
 7
Author: Perpetualcoder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-17 06:01:14

Si el nombre del campo es diferente en entidades

var result = from x in entity
   join y in entity2 on 
          new {
                field1=   x.field1,
               field2 =  x.field2 
             } 
          equals
         new { 
                field1= y.field1,
                field2=  y.myfield
              }
select new {x,y});
 1
Author: Mahesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-02 02:56:08

Declare una Clase(Tipo) para contener los elementos a los que desea unirse. En el siguiente ejemplo declare JoinElement

 public class **JoinElement**
{
    public int? Id { get; set; }
    public string Name { get; set; }

}

results = from course in courseQueryable.AsQueryable()
                  join agency in agencyQueryable.AsQueryable()
                   on new **JoinElement**() { Id = course.CourseAgencyId, Name = course.CourseDeveloper } 
                   equals new **JoinElement**() { Id = agency.CourseAgencyId, Name = "D" } into temp1
 0
Author: Ven,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-27 09:53:11

Como una cadena de métodos completa que se vería así:

lista.SelectMany(a => listb.Where(xi => b.Id == a.Id && b.Total != a.Total),
                (a, b) => new ResultItem
                {
                    Id = a.Id,
                    ATotal = a.Total,
                    BTotal = b.Total
                }).ToList();
 0
Author: Adam Garner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-16 09:41:58
from d in db.CourseDispatches
                             join du in db.DispatchUsers on d.id equals du.dispatch_id
                             join u in db.Users on du.user_id equals u.id
                             join fr in db.Forumreports on (d.course_id + '_' + du.user_id)  equals  (fr.course_id + '_'+ fr.uid)

Esto funciona para mí

 -2
Author: user2745564,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-12 02:13:51