c# - optionsbuilder - Usando DbContext Set<T>() en lugar de exponer en el contexto
optionsbuilder usesqlserver connection string (5)
¿Hay alguna diferencia al hacer lo siguiente?
public class UsersContext : DbContext
{
public DbSet<User> Users { get; set; }
}
versus usar el método Set<T>
del contexto:
public class UsersContext : DbContext
{
}
var db = new UsersContext();
var users = db.Set<User>();
Estos efectivamente hacen lo mismo, dándome un conjunto de Usuarios, pero ¿hay alguna diferencia diferente a la que usted no está exponiendo el conjunto a través de una propiedad?
Así es como configuro mi dbSet genérico, funciona bien
DbContext context = new MyContext();
DbSet<T> dbSet = context.Set<T>();
Es la versión genérica de algo más explícito, como
DbContext context = new MyContext();
DbSet<User> dbSet = context.Set<User>();
De cualquier manera, son los mismos (cuando T
es User
)
Creo que hay alguna diferencia. Déjame usar el ejemplo como en la pregunta. Supongamos que quiero hacer un Any basado en User.FirstName y User.LastName (la tabla de usuarios tiene más campos)
UsersContext.Users.Any(u => u.FirstName.ToLower() == userObj.FirstName && u.LastName.ToLower() == userObj.LastName);
: UsersContext.Users.Any(u => u.FirstName.ToLower() == userObj.FirstName && u.LastName.ToLower() == userObj.LastName);
Método2: (UsersContext.Set(typeof(User)) as IQueryable<User>).Any(u => u.FirstName.ToLower() == userObj.FirstName && u.LastName.ToLower() == userObj.LastName);
Verifiqué en el generador de perfiles SQL la consulta activada en el Método 1 es:
exec sp_executesql N''SELECT
CASE WHEN ( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[User] AS [Extent1]
WHERE (((LOWER([Extent1].[FirstName])) = (LOWER(@p__linq__0))) AND ((LOWER([Extent1].[LastName])) = @p__linq__1)
)) THEN cast(1 as bit) WHEN ( NOT EXISTS (SELECT
1 AS [C1]
FROM [dbo].[User] AS [Extent2]
WHERE (((LOWER([Extent2].[FirstName])) = (LOWER(@p__linq__0))) AND ([Extent2].[LastName] = @p__linq__1)
)) THEN cast(0 as bit) END AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable1]'',@p__linq__0 nvarchar(4000),@p__linq__1 nvarchar(4000)'',@p__linq__0=N''jack'',@p__linq__1=N''saw''
De Method2:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[FirstName] AS [FirstName],
[Extent1].[LastName] AS [LastName],
[Extent1].[Email] AS [Email],
.......other fields......
FROM [dbo].[Users] AS [Extent1]
La tabla tiene 40000 registros y Method1 toma alrededor de 20 ms, mientras que Method2 toma alrededor de 3500 ms.
Creo que no hay tal diferencia entre dos enfoques, excepto que Set<User>()
es más adecuado para implementar patrones de acceso a datos como el patrón de Repository
debido a la naturaleza genérica del método Set<T>()
.
La propiedad Users
se agrega para su conveniencia, por lo que no necesita recordar qué son todas sus tablas y cuál es la clase correspondiente, puede usar Intellisense para ver todas las tablas con las que el contexto fue diseñado para interactuar. El resultado final es funcionalmente equivalente a usar Set<T>
.
Obtendrá un beneficio con el método anterior cuando use las migraciones de Code-First, ya que las nuevas entidades se detectarán automáticamente. De lo contrario, estoy bastante seguro de que son equivalentes.