传统技术警告:不建议使用ASP.NET MVC。 建议使用ASP.NET Core。 但是,如果您有兴趣,请阅读。
我决定略微扩展
以前有关ASP.NET MVC和MySQL的文章 。 这是关于在ASP.NET MVC中使用MySQL而不是通过几乎标准的ORM实体框架(EF),而是通过ADO.NET直接访问DBMS。 并给出了该访问方法的实现。 而且,尽管该方法已经过时并且不建议使用,但它有时还是有用的:例如,在高负载的应用程序中或开发人员遇到ORM无法生成正确的SQL查询的情况时。 有时,您可以在应用程序中结合使用这两种方法-通过ORM和ADO.NET。 结果,我想到并决定完成该应用程序:向其添加Entity Framework的存储库实现,并使用Dependency Resolver依赖于应用程序参数来选择它们。
所有代码都可以在此处获取,下面的代码将部分地带有小链接和与
上一个项目有关的解释。 在这里您可以
看到该应用程序 。
我们改变项目
1.要将Entity Framework与MySQL一起使用,我们需要安装
MySQL.Data.EntityFramework库(当然,您可以拥有另一个库,就是MySQL所有者Oracle的一个库)。

它将拉
MySQL.Data和
EntityFramework本身 。 对
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>
与
MySQL.Data发生了
一个有趣的冲突-由于
MySQL.Data.EntityFramework要求
MySQL.Data的版本至少为8.0.19,因此已对其进行更新...并且该项目停止了工作。 开始出现错误:

«Ubiety.Dns.Core» . . , , . ( HRESULT: 0x80131045)
显然,
未签名的程序集Ubiety.Dns.Core已添加到
MySQL.Data 8.0.19中 。 我还必须通过Nuget将这个组件包括在项目中。 错误消失了。
2.另外,要实现依赖关系的实现,我们将Ninject添加到项目中-用于实现依赖关系(DI)的容器。
3.我们将略微改变项目结构:将存储库文件放到单独的
存储库目录中,并在其中创建
ADO.NET子目录(我们将在其中转移现有
LanguagesRepository.cs和
UsersRepository.cs文件)和
EF (此处将提供实体框架的存储库文件)。
4.另外,在
appConfig
部分的
web.config文件中添加了一个应用程序参数:
<add key="ConnectionMethod" value="ADO.NET" />
。 该应用程序将采用两个值:“实体框架”或“ ADO.NET”。 在
Base.cs文件中
添加了此参数
的链接:
public static string ConnectionMethod { get { return System.Configuration.ConfigurationManager.AppSettings["ConnectionMethod"]; } }
实体框架和MySQL-存储库
将具有
EFDbContext
类的
DbContext.cs文件添加到
Repository \ EF EFDbContext
:
public class EFDbContext : DbContext { public EFDbContext() : base(Base.ConnectionString) { } public DbSet<UserClass> Users { get; set; } public DbSet<LanguageClass> Languages { get; set; } }
在其中,我们确定使用的DBMS连接字符串以及“
Users
和
Languages
数据集。
使用
LanguagesRepositoryEF
类添加
LanguagesRepository.cs文件:
public class LanguagesRepositoryEF : ILanguagesRepository { private EFDbContext context = new EFDbContext(); public IList<LanguageClass> List() { return context.Languages.OrderBy(x => x.LanguageName).ToList(); } }
以及具有
UsersRepositoryEF
类的
UsersRepository.cs文件:
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; } }
可以看出,文件大小明显比ADO.NET短(ORM为我们做了肮脏的工作),它自己创建了SQL查询。
但是,我遇到了一些要点,这些要点融入了ADO.NET的实现中,但是在EF中不起作用。
我必须对
UserClass.cs文件(在
Domain目录中)进行更改的第一件事:为
Users
和
Languages
表之间的连接的正常操作添加另一个字段:
[HiddenInput(DisplayValue = false)] public int? LanguageID { get; set; }
第二点-事实证明,MySQL中的字段(例如
Enum
无法通过EF使用。 最有可能的原因是代码中的枚举是整数值,但是从数据库中通过EF的值被读取为文本(如果在从MySQL查询以读取枚举类型的字段的值中,MySQL仅返回此枚举的文本值)。 如果在ADO.NET版本中我可以使用
CAST(u.SupporterTier AS UNSIGNED) as SupporterTier
构造来解决此问题,那么对于EF而言,这种变形对我来说是无法克服的-没有一个尝试过的选项出现。 好吧,由于
Code First技术生成的
Enum
类型的字段作为INT类型的字段,因此我们不得不在数据库中更改
SupporterTier
字段的类型:
CHANGE COLUMN `SupporterTier` `SupporterTier` INT(4) UNSIGNED NOT NULL DEFAULT '1' ;
使用应用程序参数选择存储库
我们将通过构造函数使用实现,就像在教科书中写的那样。 首先,我们需要为共享存储库创建接口:在
Repository目录中创建
LanguagesRepository.cs文件,其内容如下:
public interface ILanguagesRepository { IList<LanguageClass> List(); }
以及具有内容的
UsersRepository.cs文件:
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); }
好吧,我们从这些接口继承相应的类:
public class LanguagesRepositoryADO : ILanguagesRepository public class UsersRepositoryADO : IUsersRepository public class LanguagesRepositoryEF : ILanguagesRepository public class UsersRepositoryEF : IUsersRepository
好吧,在
UsersController控制器中
,我们进行了添加,使其可以与以下接口一起使用:
private ILanguagesRepository repLanguages; private IUsersRepository repUsers; public UsersController(ILanguagesRepository langsParam, IUsersRepository usersParam) { repLanguages = langsParam; repUsers = usersParam; }
在控制器中,我们将访问这些类的
repUsers
分别更改为
repLanguages
和
repUsers
。 但是我们需要通过控制器构造函数传递存储库类的实例,这当然很不方便。 为了避免这种情况,我们需要强大的功能,例如
依赖解析器 (DR)。 为此,我们将使用Ninject:
我们在
Application_Start
方法的
Global.asax.cs文件中注册DR:
DependencyResolver.SetResolver(new NinjectDependencyResolver());
使用
NinjectDependencyResolver
类(从
IDependencyResolver
接口继承)在
Infrastructure目录中创建
NinjectDependencyResolver.cs文件:
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>(); } } }
结果发现,唯一确定使用哪种方法(直接通过ADO.NET或通过实体框架)使用
AddBindings
方法是
NinjectDependencyResolver
类中的
AddBindings
方法。 如果您不知道它是如何工作的,那真是不可思议。
在
AddBindings
方法中,取决于ConnectionMethod应用程序参数的值,
ILanguagesRepository
和
IUsersRepository
与实现接口方法的特定类。 自从
NinjectDependencyResolver
应用程序以来,我们将DR注册为
NinjectDependencyResolver
类的对象,并且在该类中,我们指定了存储库接口与特定类的绑定,因此当请求MVC框架创建
UsersController
控制器
UsersController
,Ninject在分析该类时会发现它需要实现
ILanguagesRepository
和
IUsersRepository
,将创建特定类的实例,并将它们传递给控制器构造函数(通过DR和MVC框架)。
合计
该应用程序现在支持通过ORM实体框架访问DBMS的方法。 同时,通过ADO.NET的访问方法并没有消失,而是在通过参数启动应用程序时选择了访问方法,为此,我们使用Ninject库通过控制器构造函数使用了依赖项注入方法。

PS最后:您可以在
此地址查看该项目的工作方式。
在这里您可以下载整个项目。 好了,到堆-
我的博客的链接。