Tecnología heredadaAdvertencia: ASP.NET MVC ya está en desuso. Se recomienda el uso de ASP.NET Core. Pero si estás interesado, entonces lee.
Decidí ampliar ligeramente el
artículo anterior sobre ASP.NET MVC y MySQL . Se trataba de trabajar con MySQL en ASP.NET MVC no a través de ORM Entity Framework (EF) casi estándar, sino usando el acceso directo al DBMS a través de ADO.NET. Y se dio una implementación de este método de acceso. Y aunque el método está desactualizado y no se recomienda su uso, a veces es útil: por ejemplo, en aplicaciones altamente cargadas o cuando un desarrollador se enfrenta a una situación en la que ORM no puede generar una consulta SQL que funcione correctamente. Y a veces puede combinar ambos métodos en una aplicación, tanto a través de ORM como a través de ADO.NET. Como resultado, pensé y decidí terminar la aplicación: agregarle una implementación de repositorio para Entity Framework y hacer que la elección de ellos dependa del parámetro de la aplicación usando el Dependency Resolver.
Todo el código se puede tomar aquí en
esta dirección , debajo de este código se presentará parcialmente con pequeños enlaces y explicaciones en relación con el
proyecto anterior . Y aquí puedes
ver la aplicación .
Cambiamos el proyecto
1. Para usar Entity Framework con MySQL, necesitamos instalar la biblioteca
MySQL.Data.EntityFramework (por supuesto, puede tener otra, solo esta de Oracle, el propietario de MySQL).
Extraerá MySQL.Data y
EntityFramework . Se realizaron los siguientes cambios en el
archivo web.config :
<entityFramework> <providers> <provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.EntityFramework, Version=8.0.19.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" /> </providers> </entityFramework>
Surgió un conflicto interesante con
MySQL.Data , ya que
MySQL.Data.EntityFramework requería una versión de
MySQL.Data de al menos 8.0.19, se actualizó ... y el proyecto dejó de funcionar. Un error comenzó a ocurrir:

«Ubiety.Dns.Core» . . , , . ( HRESULT: 0x80131045)
Aparentemente, el
ensamblado sin firmar Ubiety.Dns.Core se agregó a
MySQL.Data 8.0.19 . También tuve que incluir este componente a través de Nuget en el proyecto. El error se ha ido.
2. Además, para implementar la implementación de dependencias, agregamos al proyecto Ninject: el contenedor para implementar dependencias (DI).
3. Cambiaremos ligeramente la estructura del proyecto:
colocaremos los archivos del repositorio en un directorio de
Repositorio separado y crearemos los subdirectorios
ADO.NET en él (transferiremos los archivos existentes de
LanguagesRepository.cs y
UsersRepository.cs allí ) y
EF (habrá archivos de repositorio para Entity Framework aquí).
4. Además, se ha agregado un parámetro de aplicación al
archivo web.config en la sección
appConfig
:
<add key="ConnectionMethod" value="ADO.NET" />
. La aplicación tomará dos valores: "Entity Framework" o "ADO.NET".
Se agregó un enlace a este parámetro al archivo
Base.cs :
public static string ConnectionMethod { get { return System.Configuration.ConfigurationManager.AppSettings["ConnectionMethod"]; } }
Entity Framework y MySQL - repositorio
Agregue el archivo
DbContext.cs con la clase
EFDbContext
al
EFDbContext
Repository \ EF :
public class EFDbContext : DbContext { public EFDbContext() : base(Base.ConnectionString) { } public DbSet<UserClass> Users { get; set; } public DbSet<LanguageClass> Languages { get; set; } }
En él, determinamos la cadena de conexión DBMS utilizada y los conjuntos de datos de
Users
e
Languages
.
Agregue el archivo
LanguagesRepository.cs con la clase
LanguagesRepositoryEF
:
public class LanguagesRepositoryEF : ILanguagesRepository { private EFDbContext context = new EFDbContext(); public IList<LanguageClass> List() { return context.Languages.OrderBy(x => x.LanguageName).ToList(); } }
Y el archivo
UsersRepository.cs con la clase
UsersRepositoryEF
:
public class UsersRepositoryEF : IUsersRepository { private EFDbContext context = new EFDbContext(); public IList<UserClass> List() { return context.Users.ToList(); } public IList<UserClass> List(string sortName, SortDirection sortDir, int page, int pageSize, out int count) { count = context.Users.Count(); if (sortName != null) return context.Users.OrderByDynamic(sortName, sortDir).Skip((page - 1) * pageSize).Take(pageSize).ToList(); else return context.Users.OrderBy(o => o.UserID).Skip((page - 1) * pageSize).Take(pageSize).ToList(); } public bool AddUser(UserClass user) { user.Language = context.Languages.Find(user.Language.LanguageID); if (user.Language != null && context.Users.Add(user) != null) { try { context.SaveChanges(); } catch (System.Exception ex) {} } return user.UserID > 0; } public UserClass FetchByID(int userID) { UserClass user = null; try { user = context.Users.Find(userID); } catch (System.Exception ex) { } return user; } public bool ChangeUser(UserClass user) { bool result = false; user.Language = context.Languages.Find(user.Language.LanguageID); if (user.Language != null) { UserClass olduser = context.Users.Find(user.UserID); if (olduser != null) { olduser.Email = user.Email; olduser.Loginname = user.Loginname; olduser.Language = user.Language; olduser.SupporterTier = user.SupporterTier; try { result = context.SaveChanges() > 0; } catch (System.Exception ex) { } } } return result; } public bool RemoveUser(UserClass user) { bool result = false; UserClass olduser = context.Users.Find(user.UserID); if (olduser != null) context.Users.Remove(olduser); try { result = context.SaveChanges() > 0; } catch (System.Exception ex) { } return result; } }
Se puede ver que el tamaño del archivo es claramente más corto que el de ADO.NET - ORM hace el trabajo sucio por nosotros - crea consultas SQL por sí solo.
Sin embargo, me encontré con un par de puntos que llegaron a la implementación de ADO.NET, pero no funcionaron en EF.
Lo primero que tuve que hacer fue cambiar el archivo
UserClass.cs (en el directorio de
Dominio ): agregue otro campo para el funcionamiento normal de la conexión entre las tablas de
Users
e
Languages
:
[HiddenInput(DisplayValue = false)] public int? LanguageID { get; set; }
Y el segundo: resultó que los campos en MySQL como
Enum
no funcionan a través de EF. Lo más probable es que la razón de esto sea que la enumeración en el código es un valor entero, pero desde la base de datos los valores a través de EF se leen como texto (si en una consulta de MySQL para leer los valores de un campo de tipo enum, MySQL devuelve solo los valores de texto de esta enumeración). Y si en la versión para ADO.NET puedo
CAST(u.SupporterTier AS UNSIGNED) as SupporterTier
esto usando
CAST(u.SupporterTier AS UNSIGNED) as SupporterTier
construcción de
CAST(u.SupporterTier AS UNSIGNED) as SupporterTier
, entonces con EF tal metamorfosis resultó ser insuperable para mí, ninguna de las opciones probadas surgió. Bueno, dado que la tecnología
Code First genera un campo de tipo
Enum
como un campo de tipo INT, tuvimos que cambiar el tipo del campo
SupporterTier
en la base de datos:
CHANGE COLUMN `SupporterTier` `SupporterTier` INT(4) UNSIGNED NOT NULL DEFAULT '1' ;
Seleccione el repositorio usando el parámetro de la aplicación
Usaremos la implementación a través del constructor, tal como está escrito en el libro de texto. Primero, necesitamos crear interfaces para nuestro repositorio compartido: cree el archivo
LanguagesRepository.cs en el directorio
Repository con los contenidos:
public interface ILanguagesRepository { IList<LanguageClass> List(); }
Y el archivo
UsersRepository.cs con el contenido:
public interface IUsersRepository { IList<UserClass> List(); IList<UserClass> List(string sortName, SortDirection sortDir, int page, int pageSize, out int count); bool AddUser(UserClass user); UserClass FetchByID(int userID); bool ChangeUser(UserClass user); bool RemoveUser(UserClass user); }
Bueno, heredamos las clases correspondientes de estas interfaces:
public class LanguagesRepositoryADO : ILanguagesRepository public class UsersRepositoryADO : IUsersRepository public class LanguagesRepositoryEF : ILanguagesRepository public class UsersRepositoryEF : IUsersRepository
Bueno, en el controlador
UsersController, hacemos adiciones que le permitirán trabajar con estas interfaces:
private ILanguagesRepository repLanguages; private IUsersRepository repUsers; public UsersController(ILanguagesRepository langsParam, IUsersRepository usersParam) { repLanguages = langsParam; repUsers = usersParam; }
Y en el controlador, cambiamos los lugares de acceso a los objetos de estas clases a los
repUsers
repLanguages
y
repUsers
, respectivamente. Pero necesitamos pasar instancias de las clases de repositorio a través del constructor del controlador, lo que, por supuesto, es inconveniente. Para evitar esto, necesitamos hechicería fuerte como
Dependency Resolver (DR). Y para esto usaremos Ninject:
Registramos DR en el archivo
Global.asax.cs en el método
Application_Start
:
DependencyResolver.SetResolver(new NinjectDependencyResolver());
Cree el archivo
NinjectDependencyResolver.cs en el directorio
Infraestructura con la clase
NinjectDependencyResolver
(heredada de la interfaz
IDependencyResolver
):
public class NinjectDependencyResolver : IDependencyResolver { private IKernel kernel; public NinjectDependencyResolver() { kernel = new StandardKernel(); AddBindings(); } public object GetService(Type serviceType) { return kernel.TryGet(serviceType); } public IEnumerable<object> GetServices(Type serviceType) { return kernel.GetAll(serviceType); } private void AddBindings() { if (Domain.Base.ConnectionMethod == "Entity Framework") { kernel.Bind<ILanguagesRepository>().To<LanguagesRepositoryEF>(); kernel.Bind<IUsersRepository>().To<UsersRepositoryEF>(); } else { kernel.Bind<ILanguagesRepository>().To<LanguagesRepositoryADO>(); kernel.Bind<IUsersRepository>().To<UsersRepositoryADO>(); } } }
Y resulta que el único lugar en el que se determina qué método de trabajo con el DBMS se usa (directamente, a través de ADO.NET oa través del Entity Framework) es el método
AddBindings
en la clase
NinjectDependencyResolver
. Magia real si no sabes cómo funciona.
En el método
AddBindings
, dependiendo del valor del parámetro de aplicación ConnectionMethod, las
IUsersRepository
ILanguagesRepository
e
IUsersRepository
con clases específicas que implementan los métodos de interfaz. Desde que
NinjectDependencyResolver
aplicación, registramos DR como un objeto de la clase
NinjectDependencyResolver
, y en la clase especificamos el enlace de las interfaces del repositorio a una clase específica, al solicitar el marco MVC para crear el
UsersController
controlador UsersController, Ninject al analizar la clase encontrará que requiere la implementación de las
IUsersRepository
ILanguagesRepository
e
IUsersRepository
creará instancias de clases específicas y las pasará al constructor del controlador (a través de DR y el marco MVC).
Total
La aplicación ahora también admite el método de acceso al DBMS a través de ORM Entity Framework. Al mismo tiempo, el método de acceso a través de ADO.NET no ha desaparecido y se selecciona cuando el parámetro inicia la aplicación, para lo cual utilizamos el método de inyección de dependencia a través del constructor del controlador utilizando la biblioteca Ninject.

PD Y finalmente: puedes ver cómo funciona este proyecto en
esta dirección . Y
aquí puedes descargar todo el proyecto. Bueno, para el montón: un enlace a
mi blog .