Overview
Entity Framework Core te permite trabajar con datos en tu aplicación sin ejecutar explícitamente comandos de base de datos. Para consultar sus datos, utilice la sintaxis de query integrada en el lenguaje (LINQ). LINQ te permite guardar queries fuertemente tipadas utilizando palabras clave y operadores específicos de C#. Cuando ejecutas la aplicación, el proveedor de EF Core traduce automáticamente las consultas LINQ y las ejecuta en la base de datos utilizando la API de consultas de MongoDB.
En esta guía, puedes ver ejemplos de operaciones de query comunes en una aplicación configurada para utilizar el proveedor EF Core.
Tip
Para aprender a configurar una aplicación para usar el Proveedor EF Core, consulte Configurar el Proveedor EF Core.
Datos de muestra
Los ejemplos de esta guía utilizan la colección planets de la base de datos sample_guides. Los documentos de esta colección utilizan la siguiente clase Planet como modelo:
public class Planet { public ObjectId _id { get; set; } public string name { get; set; } = null!; public int orderFromSun { get; set; } public bool hasRings { get; set; } }
Esta colección proviene del conjunto de conjuntos de datos de muestra provistos por Atlas. Consulta la guía Inicio rápido para aprender a crear un clúster gratuito de MongoDB y cargar estos datos de muestra.
Buscar entidades
Encuentra una sola entidad usando el método FirstOrDefault(), o encuentra varias entidades usando el método Where().
Encuentra una entidad individual
El método FirstOrDefault() devuelve la primera entidad que encuentra en tu colección que coincide con los criterios de búsqueda y devuelve null si no se encuentran entidades coincidentes.
El siguiente código utiliza el método FirstOrDefault() para encontrar un planeta en el campo name de “Mercurio” a partir de un DBSet llamado Planets e imprime el nombre del planeta en la consola:
var planet = db.Planets.FirstOrDefault(p => p.name == "Mercury"); Console.WriteLine(planet?.name);
Encontrar varios entidades
Puedes utilizar el método Where() para recuperar múltiples entidades de tus colecciones. Where() devuelve todas las entidades que coinciden con los criterios de búsqueda.
El siguiente código usa el método Where() para encontrar todos los planetas que tengan el campo hasRings establecido en true e imprime los nombres de los planetas en la consola.
var planets = db.Planets.Where(p => p.hasRings); foreach (var p in planets) { Console.WriteLine(p.name); }
Query a Shadow Property
Una propiedad en la sombra es una propiedad que no está definida en su clase de entidad .NET, pero que está incluida en el modelo de Entity Framework y está mapeada a campos en la base de datos. Puede utilizar las propiedades ocultas para query o rastrear datos en sus documentos sin exponerlo como una propiedad en su entidad.
Para hacer referencia a una propiedad sombra en una query LINQ, llama al método EF.Property<T>() y pasa el nombre de la propiedad configurada como argumento. El argumento de tipo genérico debe coincidir con el tipo de datos de la propiedad shadow.
Por ejemplo, la clase Planet no define una propiedad para el campo mainAtmosphere. Para configurar este campo como una propiedad sombra, llame al método Property<T>() en el método OnModelCreating() de PlanetDbContext, como se muestra en el siguiente ejemplo:
public class PlanetDbContext : DbContext { public DbSet<Planet> Planets { get; init; } = null!; public static PlanetDbContext Create(IMongoDatabase database) => new(new DbContextOptionsBuilder<PlanetDbContext>() .UseMongoDB(database.Client, database.DatabaseNamespace.DatabaseName) .Options); public PlanetDbContext(DbContextOptions options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<Planet>().ToCollection("planets"); modelBuilder.Entity<Planet>().Property<string[]>("mainAtmosphere"); } }
La llamada a modelBuilder.Entity<Planet>().Property<string[]>("mainAtmosphere") le indica al framework que incluya mainAtmosphere en el modelo y lo asigne a un campo string[] en MongoDB.
El siguiente código utiliza el método EF.Property<string[]>() para encontrar todos los planetas que tienen una propiedad de sombra mainAtmosphere no vacía y imprime los nombres de los planetas en la consola:
var planets = db.Planets.Where( p => EF.Property<string[]>(p, "mainAtmosphere").Length > 0); foreach (var p in planets) { Console.WriteLine(p.name); }
Verificar la existencia del campo
Puede realizar una query de documentos en función de si un campo existe, falta o tiene un valor null usando métodos en la clase Mql.
Nota
Estos métodos funcionan tanto con propiedades reales como con propiedades en sombra.
Mql.Exists
El método Mql.Exists() coincide con los documentos que contienen el campo especificado, incluidos los documentos en los que el valor del campo es null.
El siguiente código utiliza el método Mql.Exists() para encontrar todos los planetas que tienen el campo hasRings e imprime los nombres de los planetas en la consola:
var planetNames = db.Planets .Where(p => Mql.Exists(p.hasRings)) .Select(p => p.name); foreach (var name in planetNames) { Console.WriteLine(name); }
Mql.IsMissing
El método Mql.IsMissing() coincide con los documentos que no contienen el campo especificado.
El siguiente código utiliza el método Mql.IsMissing() para encontrar todos los planetas que no tienen el campo hasRings e imprime los nombres de los planetas en la consola:
var planetNames = db.Planets .Where(p => Mql.IsMissing(p.hasRings)) .Select(p => p.name); foreach (var name in planetNames) { Console.WriteLine(name); }
Mql.IsNullOrMissing
El método Mql.IsNullOrMissing() encuentra los documentos en los que el campo especificado está ausente o tiene un valor null.
El siguiente código utiliza el método Mql.IsNullOrMissing() para encontrar todos los planetas donde el campo hasRings falta o null e imprime los nombres de los planetas en la consola:
var planetNames = db.Planets .Where(p => Mql.IsNullOrMissing(p.hasRings)) .Select(p => p.name); foreach (var name in planetNames) { Console.WriteLine(name); }
Ordenar entidades
Usa el método OrderBy() para especificar un orden en el que devolver las entidades de una query. OrderBy() ordena los elementos en orden ascendente según un criterio de clasificación especificado.
El siguiente código utiliza el método OrderBy() para encontrar todos los planetas y ordenarlos por el valor del campo orderFromSun en orden ascendente. Luego imprime los resultados en la consola.
var planetList = db.Planets.OrderBy(p => p.orderFromSun); foreach (var p in planetList) { Console.WriteLine(p.name); }
{"_id":"...","name":"Mercury","orderFromSun":1,"hasRings":false} {"_id":"...","name":"Venus","orderFromSun":2,"hasRings":false} {"_id":"...","name":"Earth","orderFromSun":3,"hasRings":false} {"_id":"...","name":"Mars","orderFromSun":4,"hasRings":false} {"_id":"...","name":"Jupiter","orderFromSun":5,"hasRings":true} {"_id":"...","name":"Saturn","orderFromSun":6,"hasRings":true} {"_id":"...","name":"Uranus","orderFromSun":7,"hasRings":true} {"_id":"...","name":"Neptune","orderFromSun":8,"hasRings":true}
Tip
Ordenar en orden descendente
Puedes ordenar los resultados de una query en orden descendente utilizando el método OrderByDescending().
Puedes realizar una clasificación secundaria en tu query utilizando el método ThenBy(). El método ThenBy() ordena los resultados del método OrderBy() en orden ascendente según un criterio de ordenación especificado. El método ThenBy() debe encadenarse al método OrderBy().
Tip
Ordenación secundaria en orden descendente
Puedes realizar una ordenación secundaria en orden descendente utilizando el método ThenByDescending().
El siguiente código utiliza los métodos OrderBy() y ThenBy() para encontrar todos los planetas y ordenarlos por el campo hasRings(), con una ordenación secundaria por el campo name.
var planetList = db.Planets.OrderBy(o => o.hasRings).ThenBy(o => o.name); foreach (var p in planetList) { Console.WriteLine("Has rings: " + p.hasRings + ", Name: " + p.name); }
{"_id":"...","name":"Earth","orderFromSun":3,"hasRings":false} {"_id":"...","name":"Mars","orderFromSun":4,"hasRings":false} {"_id":"...","name":"Mercury","orderFromSun":1,"hasRings":false} {"_id":"...","name":"Venus","orderFromSun":2,"hasRings":false} {"_id":"...","name":"Jupiter","orderFromSun":5,"hasRings":true} {"_id":"...","name":"Neptune","orderFromSun":8,"hasRings":true} {"_id":"...","name":"Saturn","orderFromSun":6,"hasRings":true} {"_id":"...","name":"Uranus","orderFromSun":7,"hasRings":true}
Tip
Al ordenar campos con un valor booleano, las entidades con un valor de campo de false se muestran antes que aquellas con un valor de true.
Limitar el número de resultados
Utiliza el método Take() para especificar un número máximo de entidades a devolver en una query.
El siguiente código utiliza el método Take() para devolver los primeros 3 planetas de la colección Planets:
var planetList = db.Planets.Take(3); foreach (var p in planetList) { Console.WriteLine(p.name); }
Omitir resultados
Utiliza el método Skip() para especificar cuántas entidades omitir antes de devolver los resultados de una consulta.
El siguiente código usa los métodos OrderBy() y Skip() para omitir los primeros 5 planetas (ordenados por orderFromSun) y devolver los planetas restantes:
var planetList = db.Planets.OrderBy(p => p.orderFromSun).Skip(5); foreach (var p in planetList) { Console.WriteLine(p.name); }
Agregaciones escalares
El proveedor de EF Core admite los siguientes métodos de agregación escalar:
Count(): Devuelve el número de elementos en una colección o el número de documentos que coinciden con un predicadoLongCount(): Devuelve el número de elementos en una colección como unlongo el número de documentos que cumplen con un predicadoAny()Devuelvetruesi algún elemento de la colección coincide con el predicadoMax()Devuelve el valor máximo de un campo especificado en una colecciónMin()Devuelve el valor mínimo de un campo especificado en una colecciónSum()Devuelve la suma de los valores de un campo especificado en una colecciónAverage(): Devuelve el promedio de valores de un campo especificado en una colección
Las siguientes secciones muestran ejemplos de cada uno de los métodos anteriores.
count
El siguiente ejemplo utiliza el método Count() para contar el número de elementos en la colección Planets:
var planetCount = db.Planets.Count(); Console.WriteLine("Planet Count: " + planetCount);
El siguiente ejemplo utiliza el método Count() para contar el número de elementos en la colección Planets que tienen un campo hasRings configurado en true:
var planetCountWithRings = db.Planets.Count(p => p.hasRings); Console.WriteLine("Planet Count with Rings: " + planetCountWithRings);
LongCount
El siguiente ejemplo utiliza el método LongCount() para contar el número de elementos en la colección Planets y devuelve el resultado como un long:
var planetCountLong = db.Planets.LongCount(); Console.WriteLine("Long Planet Count: " + planetCountLong);
El siguiente ejemplo usa el método LongCount() para contar el número de elementos en la colección Planets que tienen el campo hasRings configurado en true y devuelve el resultado como un long:
var planetCountLongWithRings = db.Planets.LongCount(p => p.hasRings); Console.WriteLine("Long Planet Count with Rings: " + planetCountLongWithRings);
Any
El siguiente ejemplo utiliza el método Any() para comprobar si algún elemento de la colección Planets tiene el campo hasRings configurado en true:
var results = db.Planets.Any(p => p.hasRings); Console.WriteLine("Planet with Rings: " + results);
máximo
El siguiente ejemplo utiliza el método Max() para encontrar el valor máximo del campo orderFromSun en la colección Planets:
var furthestPlanet = db.Planets.Max(p => p.orderFromSun); Console.WriteLine("Furthest Planet: " + furthestPlanet);
Min
El siguiente ejemplo utiliza el método Min() para encontrar el valor mínimo del campo orderFromSun en la colección Planets:
var closestPlanet = db.Planets.Min(p => p.orderFromSun); Console.WriteLine("Closest Planet: " + closestPlanet);
Suma
El siguiente ejemplo utiliza el método Sum() para encontrar la suma del campo orderFromSun en la colección Planets:
var totalOrderFromSun = db.Planets.Sum(p => p.orderFromSun); Console.WriteLine("Total Order From Sun: " + totalOrderFromSun);
Media
El siguiente ejemplo utiliza el método Average() para encontrar el valor promedio del campo orderFromSun en la colección Planets:
var averageOrderFromSun = db.Planets.Average(p => p.orderFromSun); Console.WriteLine("Average Order From Sun: " + averageOrderFromSun);
Inspeccionar las consultas enviadas a MongoDB
Después de escribir una consulta LINQ, revisa la consulta generada para confirmar que el proveedor está enviando la estructura esperada al MongoDB Server. Para inspeccionar consultas durante el desarrollo, habilita el registro de EF Core en tu DbContext utilizando el método LogTo() .
El siguiente ejemplo muestra cómo habilitar el registro en la consola al crear un objeto DbContext:
var mongoClient = new MongoClient("<connection string URI>"); var dbContextOptions = new DbContextOptionsBuilder<MyDbContext>() .UseMongoDB(mongoClient, "sample_guides") .LogTo(Console.WriteLine) .Options; var db = new MyDbContext(dbContextOptions);
Activar el registro de datos sensibles
El proveedor registra el texto completo de la query MQL solo cuando el registro de datos sensibles está habilitado. Si no habilita el registro de datos confidenciales, es posible que los registros de consultas omitan valores. Para habilitar el registro de datos confidenciales, llama al método EnableSensitiveDataLogging() desde tu objeto DbContextOptionsBuilder, como se muestra en el siguiente ejemplo:
var mongoClient = new MongoClient("<connection string URI>"); var dbContextOptions = new DbContextOptionsBuilder<MyDbContext>() .UseMongoDB(mongoClient, "sample_guides") .LogTo(Console.WriteLine) .EnableSensitiveDataLogging() .Options; var db = new MyDbContext(dbContextOptions);
Importante
Evitar en producción
Habilite el registro de datos confidenciales solo en entornos de desarrollo.
Convenciones de serialización personalizadas
Si registras convenciones de serialización BSON personalizadas en el MongoClient, como la nomenclatura de campos en notación camel case, esas convenciones pueden cambiar los nombres de los campos almacenados en MongoDB, de manera que difieran de los nombres de propiedades en tu modelo de entidad. El Proveedor de EF Core utiliza los nombres de las propiedades de la entidad para generar MQL, por lo que una discordancia puede provocar que las consultas se dirijan a los campos incorrectos y omitan cualquier índice en esos campos. Cuando los nombres de los campos almacenados difieren de los nombres de las propiedades de tu entidad, puedes mapear explícitamente una propiedad a su nombre de campo almacenado en OnModelCreating() usando HasElementName(), como se muestra en el siguiente ejemplo:
protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<Planet>() .Property(p => p.name) .HasElementName("name"); }
Tip
APIs de supervisión de drivers .NET/C#
Si necesitas visibilidad a un nivel inferior de los comandos de MongoDB, puedes utilizar las API de supervisión del Driver .NET/C# en tu objeto MongoClient. Para obtener más información sobre estas API, consulte Supervisión en la documentación del Driver .NET/C# .
Información Adicional
Para obtener más información sobre las agregaciones en MongoDB, consulta la guía Operaciones de agregación en el manual de MongoDB Server.
Para obtener más información sobre los métodos de EF Core tratados en esta guía, consulta los siguientes enlaces en la documentación de las API de .NET:
Para obtener más información sobre los métodos del controlador .NET/C# utilizados en esta página, consulte los siguientes enlaces a la documentación de la API:
Para aprender más sobre el método HasElementName(), consulta el siguiente enlace a la documentación de la API del proveedor de EF Core: