Legacy-TechnologieWarnung: ASP.NET MVC ist bereits veraltet. Die Verwendung von ASP.NET Core wird empfohlen. Aber wenn Sie interessiert sind, dann lesen Sie.
Ich habe beschlossen, den
vorherigen Artikel über ASP.NET MVC und MySQL etwas zu erweitern. Es ging um die Arbeit mit MySQL in ASP.NET MVC, nicht über das fast standardmäßige ORM Entity Framework (EF), sondern über den direkten Zugriff auf das DBMS über ADO.NET. Und eine Implementierung dieser Zugriffsmethode wurde gegeben. Und obwohl die Methode veraltet ist und nicht für die Verwendung empfohlen wird, ist sie manchmal nützlich: Zum Beispiel in stark ausgelasteten Anwendungen oder wenn ein Entwickler mit einer Situation konfrontiert ist, in der ORM keine ordnungsgemäß funktionierende SQL-Abfrage generieren kann. Und manchmal können Sie beide Methoden in einer Anwendung kombinieren - sowohl über ORM als auch über ADO.NET. Aus diesem Grund habe ich mir überlegt und beschlossen, die Anwendung fertigzustellen: Eine Repository-Implementierung für das Entity Framework hinzuzufügen und die Auswahl mit dem Dependency Resolver vom Anwendungsparameter abhängig zu machen.
Der gesamte Code kann hier unter
dieser Adresse abgerufen werden. Nachfolgend wird der Code teilweise mit kleinen Links und Erläuterungen zum
vorherigen Projekt dargestellt . Und hier können
Sie die Anwendung sehen .
Wir ändern das Projekt
1. Um das Entity Framework mit MySQL zu verwenden, müssen Sie die
MySQL.Data.EntityFramework- Bibliothek installieren (Sie können natürlich auch eine andere haben, nur diese von Oracle, dem Eigentümer von MySQL).

Es wird
MySQL.Data und
EntityFramework selbst ziehen . Die folgenden Änderungen wurden an der
Datei web.config vorgenommen :
<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>
Es entstand
ein interessanter Konflikt mit
MySQL.Data - da
MySQL.Data.EntityFramework eine Version von
MySQL.Data von mindestens 8.0.19 benötigte, wurde diese aktualisiert ... und das Projekt funktionierte nicht mehr. Es trat ein Fehler auf:

«Ubiety.Dns.Core» . . , , . ( HRESULT: 0x80131045)
Anscheinend wurde die
nicht signierte Assembly Ubiety.Dns.Core zu
MySQL.Data 8.0.19 hinzugefügt. Ich musste diese Komponente auch über Nuget in das Projekt einbinden. Der Fehler ist weg.
2. Um die Implementierung von Abhängigkeiten zu implementieren, fügen wir dem Projekt Ninject den Container für die Implementierung von Abhängigkeiten (DI) hinzu.
3. Wir werden die Projektstruktur geringfügig ändern: Wir werden die Repository-Dateien in einem separaten
Repository- Verzeichnis
ablegen und die
ADO.NET- Unterverzeichnisse darin erstellen (wir werden die vorhandenen
LanguagesRepository.cs- und
UsersRepository.cs- Dateien
dorthin übertragen ) und
EF (es werden Repository-Dateien für das Entity Framework hier vorhanden sein).
4. Außerdem wurde der
Datei appConfig
Abschnitt
appConfig
ein Anwendungsparameter hinzugefügt:
<add key="ConnectionMethod" value="ADO.NET" />
. Die Anwendung nimmt zwei Werte an: "Entity Framework" oder "ADO.NET".
Der Datei
Base.cs wurde ein Link zu diesem Parameter
hinzugefügt :
public static string ConnectionMethod { get { return System.Configuration.ConfigurationManager.AppSettings["ConnectionMethod"]; } }
Entity Framework und MySQL - Repository
Fügen Sie die Datei
DbContext.cs mit der
EFDbContext
Klasse zum
EFDbContext
Repository \ EF hinzu :
public class EFDbContext : DbContext { public EFDbContext() : base(Base.ConnectionString) { } public DbSet<UserClass> Users { get; set; } public DbSet<LanguageClass> Languages { get; set; } }
Darin bestimmen wir die verwendete DBMS-Verbindungszeichenfolge und die
Users
und
Languages
.
Fügen Sie die Datei
LanguagesRepository.cs mit der Klasse
LanguagesRepositoryEF
:
public class LanguagesRepositoryEF : ILanguagesRepository { private EFDbContext context = new EFDbContext(); public IList<LanguageClass> List() { return context.Languages.OrderBy(x => x.LanguageName).ToList(); } }
Und die Datei
UsersRepository.cs mit der Klasse
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; } }
Es ist zu erkennen, dass die Dateigröße deutlich geringer ist als bei ADO.NET - ORM erledigt die Dirty Work für uns - es erstellt SQL-Abfragen selbstständig.
Ich bin jedoch auf einige Punkte gestoßen, die bei der Implementierung von ADO.NET eine Rolle spielten, aber in EF nicht funktionierten.
Das erste, was ich an der
UserClass.cs- Datei (im
Domain- Verzeichnis) ändern musste: Ein weiteres Feld für den normalen Betrieb der Verbindung zwischen den Tabellen
Users
und
Languages
hinzufügen:
[HiddenInput(DisplayValue = false)] public int? LanguageID { get; set; }
Und das zweite - es stellte sich heraus, dass Felder in MySQL wie
Enum
nicht über EF funktionieren. Der Grund dafür ist höchstwahrscheinlich, dass die Aufzählung im Code ein ganzzahliger Wert ist, die Werte über EF jedoch aus der Datenbank als Text gelesen werden (wenn in einer Abfrage von MySQL zum Lesen der Werte eines Feldes vom Typ enum MySQL nur die Textwerte dieser Aufzählung zurückgibt). Und wenn ich dies in der Version für ADO.NET
CAST(u.SupporterTier AS UNSIGNED) as SupporterTier
kann, indem ich das
CAST(u.SupporterTier AS UNSIGNED) as SupporterTier
Konstrukt verwende, dann hat sich eine solche Metamorphose mit EF für mich als unüberwindbar erwiesen - keine der erprobten Optionen ergab sich. Nun, da die
Code First- Technologie ein Feld vom Typ
Enum
als Feld vom Typ INT generiert, mussten wir den Typ des Feldes
SupporterTier
in der Datenbank ändern:
CHANGE COLUMN `SupporterTier` `SupporterTier` INT(4) UNSIGNED NOT NULL DEFAULT '1' ;
Wählen Sie das Repository mit dem Anwendungsparameter aus
Wir werden die Implementierung durch den Konstruktor verwenden, so wie es im Lehrbuch geschrieben ist. Zuerst müssen wir Schnittstellen für unser freigegebenes Repository erstellen: Erstellen Sie die Datei
LanguagesRepository.cs im
Repository- Verzeichnis mit dem Inhalt:
public interface ILanguagesRepository { IList<LanguageClass> List(); }
Und die
UsersRepository.cs- Datei mit dem Inhalt:
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); }
Nun, wir erben die entsprechenden Klassen von diesen Schnittstellen:
public class LanguagesRepositoryADO : ILanguagesRepository public class UsersRepositoryADO : IUsersRepository public class LanguagesRepositoryEF : ILanguagesRepository public class UsersRepositoryEF : IUsersRepository
Nun, im
UsersController- Controller nehmen wir Ergänzungen vor, die es ihm ermöglichen, mit diesen Schnittstellen zu arbeiten:
private ILanguagesRepository repLanguages; private IUsersRepository repUsers; public UsersController(ILanguagesRepository langsParam, IUsersRepository usersParam) { repLanguages = langsParam; repUsers = usersParam; }
Und im Controller ändern wir die Stellen, an denen auf die Objekte dieser Klassen
repLanguages
auf die Objekte
repLanguages
bzw.
repUsers
. Aber wir müssen Instanzen der Repository-Klassen über den Controller-Konstruktor übergeben, was natürlich unpraktisch ist. Um dies zu vermeiden, brauchen wir starke Zauberei wie
Dependency Resolver (DR). Und dafür werden wir Ninject verwenden:
Wir registrieren DR in der Datei
Global.asax.cs in der
Application_Start
Methode:
DependencyResolver.SetResolver(new NinjectDependencyResolver());
Erstellen Sie die Datei
NinjectDependencyResolver.cs im
Infrastrukturverzeichnis mit der
NinjectDependencyResolver
Klasse (geerbt von der
IDependencyResolver
Schnittstelle):
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>(); } } }
Und es stellt sich heraus, dass die
AddBindings
Methode in der
NinjectDependencyResolver
Klasse der einzige Ort ist, an dem bestimmt wird, welche Methode für die Arbeit mit dem DBMS verwendet wird (direkt, über ADO.NET oder über das Entity Framework). Wirkliche Magie, wenn Sie nicht wissen, wie es funktioniert.
In der
AddBindings
Methode werden abhängig vom Wert des ConnectionMethod-Anwendungsparameters die
IUsersRepository
ILanguagesRepository
und
IUsersRepository
mit bestimmten Klassen verbunden, die die Schnittstellenmethoden implementieren. Seit wir
NinjectDependencyResolver
Anwendung
NinjectDependencyResolver
, haben wir DR als Objekt der
NinjectDependencyResolver
Klasse registriert. In der Klasse haben wir die Bindung der Repository-Schnittstellen an eine bestimmte Klasse angegeben, und Ninject hat bei der Analyse der Klasse festgestellt, dass die Implementierung der
ILanguagesRepository
und
IUsersRepository
erforderlich ist erstellt Instanzen bestimmter Klassen und übergibt sie an den Controller-Konstruktor (über DR und das MVC-Framework).
Total
Die Anwendung unterstützt jetzt auch die Methode des Zugriffs auf das DBMS über das ORM-Entity-Framework. Gleichzeitig ist die Zugriffsmethode über ADO.NET nicht verloren gegangen und wird beim Starten der Anwendung über den Parameter ausgewählt. Für diesen Parameter haben wir die Abhängigkeitsinjektionsmethode über den Konstruktor des Controllers unter Verwendung der Ninject-Bibliothek verwendet.

PS Und zum Schluss: Wie dieses Projekt funktioniert, sehen Sie unter
dieser Adresse . Und
hier können Sie das gesamte Projekt herunterladen. Nun, zum Haufen - ein Link zu
meinem Blog .