EntityFramework DynamicFilters实体框架高级应用之动态过滤

转自:http://www.cnblogs.com/VolcanoCloud/p/4827439.html

我们开门见山,直奔主题。

 

一、EntityFramework DynamicFilters 是什么,它能做什么?

  EntityFramework DynamicFilters是一个开源项目。你可以到这里去下载它的源码。顾名思义,它为我们做的事,就是帮我们动态过滤数据。为了照顾初学者,我们从头道来。

  1、何为数据过滤?

     数据过滤说简单点,就是去掉我们不想要的数据。SQL语句中的where从句,Linq中的where从句,还有扩展方法Where,就是完成这件光荣任务的。

 

  2、何为动态?

    动态的意思就是不死板地应用我们所写的条件,比如,我们在一个地方写了where从句,它只能用于这次查询,下次遇到相似的情况时,我们还得老老实实的写 where xxx=xxx。很长的一段时间,我们一直这样,很和谐地使用着这种方法。突然有一天,抓了抓头:如果类似的情况,能自动加上相应的过虑条件,或是应用相应的规则,该有多好?于是就有动态。当然这里的动态,只是我们面对问题的一个方面。

 

  3、废话半天,它到底能做什么,具体点,好不?

    它可以为我们创建全局的,针对实体框架查询的过虑器,这些过滤器会自动应用于每一个查询。能被用于支持多租户,软删除,等等。过滤器能通过返回布尔类型的Linq表达式来创建,同时还支持Contains()操作符(方法)。目前支持的数据库有MS SQL Server(包含 Azure),MySql,Oracle。

 

二、 没有它时,我们是怎么做的?

  我们以软删除(不是真正意义上的删除数据,只是在相应的记录上作一个删除标识)为例。正因为数据没有被真正地删除,只是被我们用一个标识给标记起来了,那么,我们就得在每一个查询的地方加上一个条件(过滤掉标记为删除的数据),代码可能长成这样:

1  var blogs = context.BlogEntries.Where(b => b.IsDeleted == false).ToList();

上面的代码就不用多解释了,相信你能看明白。 如果是sql 语句,你可能会说,这有什么难的,我找一个地方,把所有的查询拼接上这个条件不就OK。 确实如此,但,这里只是拿这个简单的场景来作为示例,复杂的场景呢?其次,Linq表达式拼接条件 ,不是像字符串那样随心所欲,至少很大一部分人是这样,当然也包含我。每一个查询都手工加上这样的条件,不光是工作量增加了,可维护性降低了,还分散了我们的核心业务逻辑的注意力。

 

三、EntityFramework DynamicFilters给我们带来了改变

  当然,它只是众多解决方案之一,只是作者无私的分享出来了,没把它当成宝供在自己的电脑里。 我只需要在上下文DbContext的OnModelCreating 方法中添加过滤器。代码如下:

复制代码
 1     protected override void OnModelCreating(DbModelBuilder modelBuilder)
 2         {
 3             base.OnModelCreating(modelBuilder);
 4 
 5             //限制所有针对BlogEntry查询的过虑(只获取未删除的)
 6             //这里的全局过虑,使用了委托,以便在每次需要计算值
 7             //重要:如果值使用的是一个委托,请确保它在你的应用中是全局的,
 8             modelBuilder.Filter("BlogEntryFilter", (BlogEntry b, bool isDeleted) => (b.IsDeleted == isDeleted),
 9                                                 () => false);
10 
11         }
复制代码

就这样,它就会在我们每一个关于Blog实体的查询中添加上条件(b => b.IsDeleted == false)。我们无需关心它如何添加这个条件,使用的地方,完全透明,就像没有它一样。示例代码如下:

复制代码
 1          /// <summary>
 2         /// 查询
 3         /// </summary>
 4         /// <param name="context"></param>
 5         /// <param name="userName"></param>
 6         private static void Query(ExampleContext context, string userName)
 7         {
 8             var account = context.Accounts
 9                 .Include(a => a.BlogEntries).FirstOrDefault(a => a.UserName == userName);

13             Console.WriteLine("账号{0}的博客有:",userName);
14             if (account == null) return;
15             foreach (var blog in account.BlogEntries)
16             {
17                 Console.WriteLine("{0}",blog.Id);
18             }
19         }    
复制代码

但需要注意的是,如果在同一个上下文DbContext实例中,运用过虑器之前,过虑器有被禁用过,而数据被缓存时,过滤器就不会起任何效果,所有使用时,你一定要避免在同一个上下文中因更改过滤器而影响结果的情况。

如果你在某种情况下不想使用过虑器时,你可以使用如下代码将其禁用:

1             //禁用过滤器
2             context.DisableFilter("BlogEntryFilter");    

 

注意:禁用只对当前上下文DbContext实例有效,不影响别的上下文实例。如果你想对所有的上下文实例有效时,可以在 OnModelCreating方法中使用全局禁用函数:

1 //全局禁用过滤器
2 modelBuilder.DisableFilterGlobally("BlogEntryFilter");

 

启用的代码类似,这里就不多少了,直接看代码:

1             //启用过滤器
2             context.EnableFilter("BlogEntryFilter");
3             context.EnableAllFilters();

 

说了这么多,我们来看看运用过滤器的效果吧,代码如下:

复制代码
 1  class Program {
 2         static void Main(string[] args) {
 3 
 4             // 过滤器默认启用
 5             var context = new ExampleContext();
 6 
 7             Console.WriteLine(" 使用过滤器BlogEntryFilter进行查询");
 8             Query(context, "homer");
 9 
10             //禁用过滤器
11             context.DisableFilter("BlogEntryFilter");
12             
13             Console.WriteLine(" 禁用过滤器BlogEntryFilter进行查询");
14             Query(context, "homer");
15 
16             Console.ReadLine();
17         }
18 
19         /// <summary>
20         /// 查询
21         /// </summary>
22         /// <param name="context"></param>
23         /// <param name="userName"></param>
24         private static void Query(ExampleContext context, string userName)
25         {
26             var account = context.Accounts
27                 .Include(a => a.BlogEntries).FirstOrDefault(a => a.UserName == userName);
28 
29             Console.WriteLine("账号{0}的博客有:",userName);
30             if (account == null) return;
31             foreach (var blog in account.BlogEntries)
32             {
33                 Console.WriteLine("{0}",blog.Id);
34             }
35         }
36     }
复制代码

 

代码输出如下:

 

四、EntityFramework DynamicFilters原理概述

  它是通过在对象 DbModelBuilder 上添加扩展方法Filter实现的,核心代码如下:

复制代码
 1   private static void Filter<TEntity>(DbModelBuilder modelBuilder, string filterName, LambdaExpression predicate, params object[] valueList)
 2         {
 3             InitializeDynamicFilters(null);
 4 
 5             filterName = ScrubFilterName(filterName);
 6 
 7             modelBuilder.Conventions.Add(new DynamicFilterConvention(filterName, typeof(TEntity), predicate));
 8 
 9             //  Always add the filter to _GlobalParameterValues - need it to be able to disable it
10             _GlobalParameterValues.TryAdd(filterName, new DynamicFilterParameters());
11 
12             int numParams = predicate.Parameters == null ? 0 : predicate.Parameters.Count;
13             int numValues = valueList == null ? 0 : valueList.Length;
14             for (int i = 1; i < numParams; i++)
15             {
16                 object value = ((i - 1) < numValues) ? valueList[i - 1] : null;
17                 SetFilterGlobalParameterValue(null, filterName, predicate.Parameters[i].Name, value);
18             }
19         }
复制代码

 

整个项目的源代码不多,如果你有兴趣,请阅读源代码。文中使用的代码,请于结尾处下载。

最后,我要说明的是,文中并没有把 EntityFramework DynamicFilters的方方面面说完,只是说了一些常见的场景。更多的细节,说阅读源码,或者和大家一起实践、交流。

 

文中示例源代码下载地址:http://files.cnblogs.com/files/VolcanoCloud/EFDynamicFilterDemo.rar

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Entity Framework 是一个对象关系映射 (ORM) 框架,它可以将数据库中的表映射到 C# 类,并且可以通过这些类来操作数据库。 下面是使用 Entity Framework 编写 web 应用的一般步骤: 1. 创建一个 ASP.NET Web 应用程序 2. 安装 Entity Framework NuGet 包 3. 创建一个数据库上下文类 4. 创建实体模型类 5. 创建控制器类 6. 创建视图 以下是一个示例: 1. 创建一个 ASP.NET Web 应用程序 在 Visual Studio 中创建一个 ASP.NET Web 应用程序。 2. 安装 Entity Framework NuGet 包 在解决方案资源管理器中,右键单击项目,选择“管理 NuGet 包”。在“浏览”选项卡中搜索“Entity Framework”,然后安装它。 3. 创建一个数据库上下文类 创建一个包含数据库连接字符串的类来连接到数据库。这个类继承自 Entity Framework 的 DbContext 类。下面是一个示例: ```csharp using System.Data.Entity; public class MyDbContext : DbContext { public MyDbContext() : base("name=MyDBConnectionString") { } public DbSet<MyEntity> MyEntities { get; set; } } ``` 4. 创建实体模型类 创建一个类来表示数据库中的表。这个类应该包含表中的列作为属性。这个类也可以包含一些方法来操作表中的数据。下面是一个示例: ```csharp public class MyEntity { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } public void Save() { using (var db = new MyDbContext()) { db.MyEntities.Add(this); db.SaveChanges(); } } } ``` 5. 创建控制器类 创建一个控制器类来处理 HTTP 请求,并且调用数据库上下文来操作数据。下面是一个示例: ```csharp public class MyController : Controller { public ActionResult Index() { var db = new MyDbContext(); var entities = db.MyEntities.ToList(); return View(entities); } [HttpPost] public ActionResult Create(MyEntity entity) { entity.Save(); return RedirectToAction("Index"); } } ``` 6. 创建视图 创建一个视图来显示数据或者收集用户输入。下面是一个示例: ```html @model IEnumerable<MyEntity> <table> <thead> <tr> <th>Name</th> <th>Age</th> </tr> </thead> <tbody> @foreach (var entity in Model) { <tr> <td>@entity.Name</td> <td>@entity.Age</td> </tr> } </tbody> </table> @using (Html.BeginForm("Create", "My", FormMethod.Post)) { <div> <label>Name:</label> @Html.TextBoxFor(m => m.Name) </div> <div> <label>Age:</label> @Html.TextBoxFor(m => m.Age) </div> <button type="submit">Create</button> } ``` 这是一个简单的示例,你可以根据你的需求来修改和扩展它。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值