ASP.NET MVC & EF 构建智能查询 二、模型的设计与ModelBinder

简介: 在第一篇中,我讲解了我们要做智能查询的原因,以及基本的解决方案设计。从这篇开始我们开始讲解它的实现过程。 其实在写这一系列文章之初,我其实是想由底至上去讲解,但是我又整理了一遍代码才发现,其实如果不了解最表面的东西,也是不太好深入的。

在第一篇中,我讲解了我们要做智能查询的原因,以及基本的解决方案设计。从这篇开始我们开始讲解它的实现过程。

其实在写这一系列文章之初,我其实是想由底至上去讲解,但是我又整理了一遍代码才发现,其实如果不了解最表面的东西,也是不太好深入的。

所以我们的第二篇文章就来讲一下我们这个智能查询框架中最浅,但也是使用最频繁的部分,也就是Model。

首先我们的Entity  或者说数据库的结构如下

image

另外如下面代码,我们有一个用于传递name=value对,及查询谓词的model

   1: public ActionResult Index(QueryModel model)
   2: {
   3:     using(var db=new DbEntities())
   4:     {
   5:         var list = db.Users.Where(model).ToList();
   6:         return View(list);
   7:     }
   8: }

我命名之为QueryModel。它由Action的参数传入,再传入EF的Where扩展方法,它是构建Lambda表达式的原型,上面是我们的一个通用的查询Action的代码。

 

而QueryModel的代码为

image

QueryModel的唯一一个属性Items,是一个ConditionItem的集合,它里面存着所有的查询条件。

而ConditionItem里面的属性

  1. Field表示要查询的目标属性的名称,我们的设定它是支持子属性查询的,例如 “Profile.MyUser.Id”
  2. Method则是当前使用的谓词,它是QueryMethod的一个枚举值
  3. OrGroup是一个字符串,是一个OrGroup的多个表达式将会以Or操作符进行关联,然后再And
  4. Prefix是一个分类的前缀,我们假定一个Action可能处理多个查询条件组的时候为了分开这些查询条件而加的属性
  5. Value则是这个表达试的值

 

而我们在页面上类似

   1: <form action="" method="post">
   2: 姓名:<input id="Name" name="[Like]Name" type="text" value="" />   
   3: Email:<input id="Email" name="[Equal]Email" type="text" value="" /><br />
   4: Id: <input id="Id" name="[Equal]Id" type="text" value="" />
   5: 生日: <input id="Birthday" name="[Equal]Birthday" type="text" value="" /><br />
   6: <input type="submit" value="查询" />
   7: </form>

这样的表单,我们提交到服务器端,我们要进行ASP.NET MVC 中IModelBinder的转换,要将querystring 或 postdata中的KeyValuePair转换为我们的ConditionItem。

当然,我们除了谓词Method之外,还有Prefix以及OrGroup要从客户端提交过来所以我们就要制定一个规则

我们约定

  1. 中括号[]中的为查询谓词
  2. 小括号()中的为前缀Prefix
  3. 大括号{}中的为OrGroup

我们可以通过以下IModelBinder的实现将Request.QueryString或Request.Form中的值转换到QueryModel中:

   1: public class SearchModelBinder : IModelBinder
   2:    {
   3:        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
   4:        {
   5:            var model = (QueryModel)(bindingContext.Model ?? new QueryModel());
   6:            var dict = controllerContext.HttpContext.Request.Params;
   7:            var keys = dict.AllKeys.Where(c => c.StartsWith("["));//我们认为只有[开头的为需要处理的
   8:            if (keys.Count() != 0)
   9:            {
  10:                foreach (var key in keys)
  11:                {
  12:                    if (!key.StartsWith("[")) continue;
  13:                    var val = dict[key];
  14:                    //处理无值的情况
  15:                    if (string.IsNullOrEmpty(val)) continue;
  16:                    AddSearchItem(model, key, val);
  17:                }
  18:            }
  19:            return model; 
  20:        }
  21:  
  22:        /// <summary>
  23:        /// 将一组key=value添加入QueryModel.Items
  24:        /// </summary>
  25:        /// <param name="model">QueryModel</param>
  26:        /// <param name="key">当前项的HtmlName</param>
  27:        /// <param name="val">当前项的值</param>
  28:        public static void AddSearchItem(QueryModel model, string key, string val)
  29:        {
  30:            string field = "", prefix = "", orGroup = "", method = "";
  31:            var keywords = key.Split(']', ')', '}');
  32:            //将Html中的name分割为我们想要的几个部分
  33:            foreach (var keyword in keywords)
  34:            {
  35:                if (Char.IsLetterOrDigit(keyword[0])) field = keyword;
  36:                var last = keyword.Substring(1);
  37:                if (keyword[0] == '(') prefix = last;
  38:                if (keyword[0] == '[') method = last;
  39:                if (keyword[0] == '{') orGroup = last;       
  40:            }
  41:            if (string.IsNullOrEmpty(method)) return;
  42:            if (!string.IsNullOrEmpty(field))
  43:            {
  44:                var item = new ConditionItem
  45:                               {
  46:                                   Field = field,
  47:                                   Value = val.Trim(),
  48:                                   Prefix = prefix,
  49:                                   OrGroup = orGroup,
  50:                                   Method = (QueryMethod) Enum.Parse(typeof (QueryMethod), method)
  51:                               };
  52:                model.Items.Add(item);
  53:            }
  54:        }
  55:    }

 

当然我们还要在Global.asax中添加

   1: ModelBinders.Binders.Add(typeof (QueryModel), new SearchModelBinder());

这样我们就可以在Action中获取到相应的查询条件了

image

我们可以看到,从表单提交过来的数据我们已经正确地存放在QueryModel中了。

 

ASP.NET MVC & EF 构建智能查询 一、智能查询的需求与设计

目录
相关文章
|
存储 Shell Linux
快速上手基于 BaGet 的脚本自动化构建 .net 应用打包
本文介绍了如何使用脚本自动化构建 `.net` 应用的 `nuget` 包并推送到指定服务仓库。首先概述了 `BaGet`——一个开源、轻量级且高性能的 `NuGet` 服务器,支持多种存储后端及配置选项。接着详细描述了 `BaGet` 的安装、配置及使用方法,并提供了 `PowerShell` 和 `Bash` 脚本实例,用于自动化推送 `.nupkg` 文件。最后总结了 `BaGet` 的优势及其在实际部署中的便捷性。
1075 10
|
JSON 编解码 API
Go语言网络编程:使用 net/http 构建 RESTful API
本章介绍如何使用 Go 语言的 `net/http` 标准库构建 RESTful API。内容涵盖 RESTful API 的基本概念及规范,包括 GET、POST、PUT 和 DELETE 方法的实现。通过定义用户数据结构和模拟数据库,逐步实现获取用户列表、创建用户、更新用户、删除用户的 HTTP 路由处理函数。同时提供辅助函数用于路径参数解析,并展示如何设置路由器启动服务。最后通过 curl 或 Postman 测试接口功能。章节总结了路由分发、JSON 编解码、方法区分、并发安全管理和路径参数解析等关键点,为更复杂需求推荐第三方框架如 Gin、Echo 和 Chi。
|
前端开发 C# 开发者
.NET使用Umbraco CMS快速构建一个属于自己的内容管理系统
.NET使用Umbraco CMS快速构建一个属于自己的内容管理系统
359 12
|
弹性计算 开发框架 安全
基于云效 Windows 构建环境和 Nuget 制品仓库进行 .Net 应用开发
本文将基于云效 Flow 流水线 Windows 构建环境和云效 Packages Nuget 制品仓库手把手教你如何开发并部署一个 .NET 应用,从环境搭建到实战应用发布的详细教程,帮助你掌握 .NET 开发的核心技能。
|
Kubernetes Cloud Native Ubuntu
庆祝 .NET 9 正式版发布与 Dapr 从 CNCF 毕业:构建高效云原生应用的最佳实践
2024年11月13日,.NET 9 正式版发布,Dapr 从 CNCF 毕业,标志着云原生技术的成熟。本文介绍如何使用 .NET 9 Aspire、Dapr 1.14.4、Kubernetes 1.31.0/Containerd 1.7.14、Ubuntu Server 24.04 LTS 和 Podman 5.3.0-rc3 构建高效、可靠的云原生应用。涵盖环境准备、应用开发、Dapr 集成、容器化和 Kubernetes 部署等内容。
1014 6
|
C# Windows 开发者
超越选择焦虑:深入解析WinForms、WPF与UWP——谁才是打造顶级.NET桌面应用的终极利器?从开发效率到视觉享受,全面解读三大框架优劣,助你精准匹配项目需求,构建完美桌面应用生态系统
【8月更文挑战第31天】.NET框架为开发者提供了多种桌面应用开发选项,包括WinForms、WPF和UWP。WinForms简单易用,适合快速开发基本应用;WPF提供强大的UI设计工具和丰富的视觉体验,支持XAML,易于实现复杂布局;UWP专为Windows 10设计,支持多设备,充分利用现代硬件特性。本文通过示例代码详细介绍这三种框架的特点,帮助读者根据项目需求做出明智选择。以下是各框架的简单示例代码,便于理解其基本用法。
1492 0
|
Java Spring 自然语言处理
Spring 框架里竟藏着神秘魔法?国际化与本地化的奇妙之旅等你来揭开谜底!
【8月更文挑战第31天】在软件开发中,国际化(I18N)与本地化(L10N)对于满足不同地区用户需求至关重要。Spring框架提供了强大支持,利用资源文件和`MessageSource`实现多语言文本管理。通过配置日期格式和货币符号,进一步完善本地化功能。合理应用这些特性,可显著提升应用的多地区适应性和用户体验。
380 0
|
微服务 API Java
微服务架构大揭秘!Play Framework如何助力构建松耦合系统?一场技术革命即将上演!
【8月更文挑战第31天】互联网技术飞速发展,微服务架构成为企业级应用主流。微服务将单一应用拆分成多个小服务,通过轻量级通信机制交互。高性能Java Web框架Play Framework具备轻量级、易扩展特性,适合构建微服务。本文探讨使用Play Framework构建松耦合微服务系统的方法。Play采用响应式编程模型,支持模块化开发,提供丰富生态系统,便于快速构建功能完善的微服务。
373 0
|
SQL 开发框架 .NET
代码更简洁,开发更高效:从零开始使用Entity Framework Core与传统ADO.NET构建数据持久化层的比较
【8月更文挑战第31天】在.NET平台上开发数据驱动应用时,选择合适的ORM框架至关重要。本文通过对比传统的ADO.NET和现代的Entity Framework Core (EF Core),展示了如何从零开始构建数据持久化层。ADO.NET虽强大灵活,但需要大量手写代码;EF Core则简化了数据访问,支持LINQ查询,自动生成SQL命令,提升开发效率。从创建.NET Core项目、定义数据模型、配置`DbContext`到执行数据库操作,EF Core提供了一套流畅的API,使数据持久化层的构建变得简单直接。
459 0
|
传感器 开发框架 物联网
揭开.NET在IoT领域的神秘面纱:如何构建智能设备,让未来生活触手可及?
【8月更文挑战第28天】随着物联网技术的发展,智能设备正深入我们的生活。.NET作为跨平台开源框架,在IoT领域应用广泛。本文介绍如何利用.NET构建智能设备,通过实例展示从环境搭建到项目创建、代码编写及运行的全过程,帮助开发者快速实现IoT解决方案,开启智能设备开发的新篇章。
512 0