接手了一个用EF来做的项目,由于项目中使用的原生处理,导致很多update都是采用先select 后 update的方式来实现,同时无法批量执行逻辑如:根据订单类型统一更新状态等。所以在经过了N多查找之后 发现了一个国外写的扩展插件EntityFramework.Extended 。
Github:https://github.com/loresoft/EntityFramework.Extended
简单说一下用法:
Deleting
//delete all users where FirstName matches
context.Users
.Where(u => u.FirstName == "firstname")
.Delete();
Update
//update all tasks with status of 1 to status of 2
context.Tasks
.Where(t => t.StatusId == 1)
.Update(t => new Task { StatusId = 2 });
//example of using an IQueryable as the filter for the update
var users = context.Users.Where(u => u.FirstName == "firstname");
context.Users.Update(users, u => new User {FirstName = "newfirstname"});
看示例代码就已经很直观了。
还有2个很少被人提到的功能:
将来的查询
建立对你所需要的数据,并在第一时间在任何结果的查询列表被访问,所有数据都将在一个往返到数据库服务器中检索。降低数据查询成本。使用此功能是附加一样简单.Future()您的查询的末尾。要使用将来的查询,确保导入EntityFramework.Extensions命名空间。
将来的查询与下面的扩展方法创建...
- Future()
- FutureFirstOrDefault()
- FutureCount()
Demo
// build up queries
var q1 = db.Users
.Where(t => t.EmailAddress == "one@test.com")
.Future();
var q2 = db.Tasks
.Where(t => t.Summary == "Test")
.Future();
// this triggers the loading of all the future queries
var users = q1.ToList();
在上面的例子中,有2个查询建立起来的,只要查询中的一个被枚举,它触发两个查询的批次负载。
// base query
var q = db.Tasks.Where(t => t.Priority == 2);
// get total count
var q1 = q.FutureCount();
// get page
var q2 = q.Skip(pageIndex).Take(pageSize).Future();
// triggers execute as a batch
int total = q1.Value;
var tasks = q2.ToList();
在这个例子中,我们必须的任务列表共同senerio。为了使GUI设置寻呼控制,你需要一个总数。随着未来我们可以批量在一起的查询来获得一个数据库调用的所有数据。
将来的查询通过创建保持IQuerable适当IFutureQuery对象工作。然后IFutureQuery对象存储在IFutureContext.FutureQueries列表。然后,当IFutureQuery对象之一被枚举,它调用回IFutureContext.ExecuteFutureQueries()经由LoadAction委托。ExecuteFutureQueries建立从所有的存储IFutureQuery对象批量查询。最后,所有的IFutureQuery对象与从查询的结果进行更新。
查询结果缓存
缓存查询结果,请使用FromCache位于扩展方法EntityFramework.Extensions命名空间。下面是一个示例高速缓存查询结果。简单地构建LINQ查询,你通常会,然后追加的FromCache扩展。
//query is cached using the default settings
var tasks = db.Tasks
.Where(t => t.CompleteDate == null)
.FromCache();
//query result is now cached 300 seconds
var tasks = db.Tasks
.Where(t => t.AssignedId == myUserId && t.CompleteDate == null)
.FromCache(CachePolicy.WithDurationExpiration(TimeSpan.FromSeconds(300)));
查询结果Cache也支持标记缓存,以便您可以通过调用过期常见的缓存条目Expire上的高速缓存标记。
// cache assigned tasks
var tasks = db.Tasks
.Where(t => t.AssignedId == myUserId && t.CompleteDate == null)
.FromCache(tags: new[] { "Task", "Assigned-Task-" + myUserId });
// some update happened to Task, expire Task tag
CacheManager.Current.Expire("Task");
在CacheManager对供应商的支持。默认提供程序使用MemoryCache存储缓存条目。要创建一个自定义的供应商,实施ICacheProvider。然后,自定义提供程序将需要在登记Locator容器。
// Replace cache provider with Memcached provider
Locator.Current.Register<ICacheProvider>(() => new MemcachedProvider());
审计日志
审计日志功能将捕捉到的变化随时它们被提交到数据库实体。审核日志仅捕获那些上发生了变化,这些变化的实体,只有属性的实体。该前和记录值之后, AuditLogger.LastAudit就是在这个信息被举行,是一个ToXml()可以很容易把审计日志转换为XML,便于储存方法。
审计日志可以通过在实体上或通过流利的配置API的属性自定义。
流利的配置
// config audit when your application is starting up...
var auditConfiguration = AuditConfiguration.Default;
auditConfiguration.IncludeRelationships = true;
auditConfiguration.LoadRelationships = true;
auditConfiguration.DefaultAuditable = true;
// customize the audit for Task entity
auditConfiguration.IsAuditable<Task>()
.NotAudited(t => t.TaskExtended)
.FormatWith(t => t.Status, v => FormatStatus(v));
// set the display member when status is a foreign key
auditConfiguration.IsAuditable<Status>()
.DisplayMember(t => t.Name);
创建审核日志
var db = new TrackerContext();
var audit = db.BeginAudit();
// make some updates ...
db.SaveChanges();
var log = audit.LastLog;
问题归纳
- 为什么没有 update方法 :缺少引用 using EntityFramework.Extensions;
- 错误:无法将类型system.data.* 转化为 *.Iquery<entity>:Extended 版本与ef版本不对应,请在nuget中查询匹配版本。
- Update 无效,请跟踪sql 脚本 以区分生成的 update where条件是否正确,与lambda 的 常量.Equals(变量) 不同 他是按照顺序生成sql where的所以 生成的 是 常量 is null or 。。。。。。请注意lambda 顺序