Código linq para seleccionar un artículo

105

Me encuentro escribiendo mucho código como este para seleccionar un elemento que coincide

var item = (from x in Items where x.Id == 123 select x).First();

¿Existe una forma más limpia de hacerlo o es tan conciso como voy a conseguir?

EDITAR: Debería haber dicho "Manera más limpia usando la sintaxis linq". Ya era consciente de la sintaxis lambda y parece que esta es la única forma. Sin embargo, obtuve información útil, así que gracias a todos los que respondieron.

Mikey Hogarth
fuente
5
Personalmente evito Single()y SingleOrDefault()SI sé que los datos ya son únicos (por ejemplo, de una base de datos que tiene esa restricción, etc.), ya Single()que lo obliga a escanear el resto de la lista para encontrar un posible duplicado, pero ese soy yo. Si necesita hacer valer su singularidad en este punto, use Single()family, si no, use First()family.
James Michael Hare

Respuestas:

176

Depende de cuánto le guste la sintaxis de consulta linq, puede usar los métodos de extensión directamente como:

var item = Items.First(i => i.Id == 123);

Y si no desea lanzar un error si la lista está vacía, use FirstOrDefaultque devuelve el valor predeterminado para el tipo de elemento ( nullpara tipos de referencia):

var item = Items.FirstOrDefault(i => i.Id == 123);

if (item != null)
{
    // found it
}

Single()y SingleOrDefault()también se puede usar, pero si está leyendo de una base de datos o algo que ya garantiza la singularidad, no me molestaría, ya que tiene que escanear la lista para ver si hay duplicados y lanzamientos. First()y se FirstOrDefault()detienen en el primer partido, para que sean más eficientes.

De la familia First()y Single(), aquí es donde tiran:

  • First() - lanza si está vacío / no se encuentra, no lanza si está duplicado
  • FirstOrDefault() - devuelve el valor predeterminado si está vacío / no se encuentra, no lanza si está duplicado
  • Single() - lanza si está vacío / no se encuentra, lanza si existe un duplicado
  • SingleOrDefault() - devuelve el valor predeterminado si está vacío / no se encuentra, arroja si existe un duplicado
James Michael Hare
fuente
1
Creo que le faltan dos signos iguales allí. Debería seri.Id == 123
davehale23
18

FirstOrDefault o SingleOrDefault pueden ser útiles, dependiendo de su escenario, y si desea manejar que haya cero o más de una coincidencia:

FirstOrDefault: Devuelve el primer elemento de una secuencia, o un valor predeterminado si no se encuentra ningún elemento.

SingleOrDefault: Devuelve el único elemento de una secuencia, o un valor predeterminado si la secuencia está vacía; este método lanza una excepción si hay más de un elemento en la secuencia

No sé cómo funciona esto en una consulta linq 'desde', pero en la sintaxis lambda se ve así:

var item1 = Items.FirstOrDefault(x => x.Id == 123);
var item2 = Items.SingleOrDefault(x => x.Id == 123);
stuartd
fuente
¿Cuál es el más eficiente en términos de tiempo de DB? Si tuviera un varchar, quisiera una coincidencia exacta, pero es posible que no haya ninguno.
Piotr Kula
2
La respuesta aceptada aborda esto en su totalidad, pero esencialmente FirstOrDefault se detiene tan pronto como encuentra una coincidencia, pero SingleOrDefault debe examinar toda la lista para asegurarse de que haya exactamente una coincidencia.
stuartd
12

Estos son los métodos preferidos:

var item = Items.SingleOrDefault(x => x.Id == 123);

O

var item = Items.Single(x => x.Id == 123);
James Hill
fuente
Gracias, ¿entonces en esta situación no hay notación linq y necesito usar lambdas?
Mikey Hogarth
Eso es bastante bueno. Realmente no he usado mucho linq, por lo que no estoy seguro de haber sido consciente de estos métodos.
salario
1
El método único comprueba que el valor de retorno sea único. Entonces, si su colección es grande, puede llevar mucho tiempo. El primer método simplemente devuelve el primer elemento que coincide con el predicado.
meziantou
La respuesta de @wageoghe James no usa linq: los métodos Single y SingleOrDefault son parte de la implementación de IEnumerable.
Mikey Hogarth
12

Solo para facilitarle la vida a alguien, la consulta linq con expresión lambda

(from x in Items where x.Id == 123 select x).FirstOrDefault();

da como resultado una consulta SQL con un select top (1).

Amal
fuente
9

Eso se puede condensar mejor en esto.

var item = Items.First(x => x.Id == 123);

Su consulta actualmente está recopilando todos los resultados (y puede haber más de uno) dentro del enumerable y luego tomando el primero de ese conjunto, haciendo más trabajo del necesario.

Single / SingleOrDefault valen la pena, pero solo si desea recorrer toda la colección y verificar que la coincidencia es única además de seleccionar esa coincidencia. First / FirstOrDefault simplemente tomará la primera coincidencia y se irá, independientemente de cuántos duplicados existan realmente.

Chris Hannon
fuente
4

Puede usar la sintaxis del método de extensión:

var item = Items.Select(x => x.Id == 123).FirstOrDefault();

Aparte de eso, no estoy seguro de cuánto más conciso puede ser, sin quizás escribir sus propios métodos de extensión especializados "First" y "FirstOrDefault".

Salario
fuente
No creo que este sea el comportamiento previsto. Esta instrucción Select devuelve (en realidad no lo hace, pero selecciona para devolución) una colección de bool, uno para cada elemento de Items, el primero de lo que se devuelve como item, que se convierte simplemente en un bool. Utilice la solución de Chris Hannon
Leonardo Daga
Quizás te refieres a Wherelo opuesto a Select, que ya se ha dicho, pero esta respuesta es incorrecta. Seleccionar en c # cambia los resultados a IEnumerable <bool>, por lo que obtendrá un boolpara el primer elementox.Id == 123
bradlis7
2

Te diré lo que funcionó para mí:

int id = int.Parse(insertItem.OwnerTableView.DataKeyValues[insertItem.ItemIndex]["id_usuario"].ToString());

var query = user.First(x => x.id_usuario == id);
tbUsername.Text = query.username;
tbEmail.Text = query.email;
tbPassword.Text = query.password;

Mi identificación es la fila que quiero consultar, en este caso la obtuve de un radGrid, luego la usé para consultar, pero esta consulta devuelve una fila, luego puede asignar los valores que obtuvo de la consulta al cuadro de texto, o cualquier cosa , Tuve que asignarlos al cuadro de texto.

G Jeny Ramírez
fuente