经过上一篇,里面有测试代码,循环60万次,耗时14秒。本次我们增加缓存来优化它。

DbContextExtensions.cs

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Core.Mapping;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.ModelConfiguration;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Linq;
using EntityFramework.Extensions;
using System.Linq.Expressions; namespace EntityFrameworkSample
{
public enum AcquiredEdmType
{
TableName, FirstPrimaryKeyNameString, ColumnName
} public struct CachedEdmInfo
{
public EntitySetMapping Mapping { get; set; } public EntitySet TableEntitySet { get; set; } public Dictionary<string, string> PropertyColumnNameDic { get; set; }
} public static class DbContextExtensions
{
private readonly static Dictionary<string, CachedEdmInfo> _mappingCache = new Dictionary<string, CachedEdmInfo>(); #region 基础方法 public static string GetTableName<TEntity>(this DbContext context)
{
return GetTableName(context, typeof(TEntity));
} public static string GetTableName(this DbContext context, Type type)
{
return GetTableNameOrColumnName(context, type, AcquiredEdmType.TableName);
} public static string GetFirstPrimaryKeyName<TEntity>(this DbContext context)
{
return GetFirstPrimaryKeyName(context, typeof(TEntity));
} public static string GetFirstPrimaryKeyName(this DbContext context, Type type)
{
return GetTableNameOrColumnName(context, type, AcquiredEdmType.FirstPrimaryKeyNameString);
} public static string GetColumnName<TEntity, TProperty>(this DbContext context, Expression<Func<TEntity, TProperty>> propertyExpression)
{
return GetTableNameOrColumnName(context, typeof(TEntity), AcquiredEdmType.ColumnName, LambdaHelper.GetPropName(propertyExpression));
} public static string GetColumnName(this DbContext context, Type type, string propertyName)
{
return GetTableNameOrColumnName(context, type, AcquiredEdmType.ColumnName, propertyName);
} private static string GetTableNameOrColumnName(this DbContext context, Type type, AcquiredEdmType edmType, string propertyName = null)
{
if (context == null)
{
throw new ArgumentNullException("dbContext");
}
if (type == null)
{
throw new ArgumentNullException("type");
}
CachedEdmInfo edmInfo;
if (_mappingCache.ContainsKey(type.FullName))
{
edmInfo = _mappingCache[type.FullName];
}
else
{
MetadataWorkspace metadata = ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace; // Get the part of the model that contains info about the actual CLR types
ObjectItemCollection objectItemCollection = ((ObjectItemCollection)metadata.GetItemCollection(DataSpace.OSpace)); // Get the entity type from the model that maps to the CLR type
EntityType entityType = metadata
.GetItems<EntityType>(DataSpace.OSpace)
.Single(e => objectItemCollection.GetClrType(e) == type); // Get the entity set that uses this entity type
EntitySet entitySet = metadata
.GetItems<EntityContainer>(DataSpace.CSpace)
.Single()
.EntitySets
.Single(s => s.ElementType.Name == entityType.Name); // Find the mapping between conceptual and storage model for this entity set
EntitySetMapping mapping = metadata.GetItems<EntityContainerMapping>(DataSpace.CSSpace)
.Single()
.EntitySetMappings
.Single(s => s.EntitySet == entitySet); // Find the storage entity set (table) that the entity is mapped
EntitySet tableEntitySet = mapping
.EntityTypeMappings.Single()
.Fragments.Single()
.StoreEntitySet; edmInfo = new CachedEdmInfo
{
Mapping = mapping,
TableEntitySet = tableEntitySet
};
_mappingCache.Add(type.FullName, edmInfo);
} // Return the table name from the storage entity set
object objTableName = edmInfo.TableEntitySet.MetadataProperties["Table"].Value;
string tableName = objTableName == null ? edmInfo.TableEntitySet.Name : Convert.ToString(objTableName); switch (edmType)
{
case AcquiredEdmType.TableName:
return tableName;
case AcquiredEdmType.FirstPrimaryKeyNameString:
{
var firstKeyProp = edmInfo.TableEntitySet.ElementType.KeyProperties[];
//return tableName + "." + firstKeyProp.Name;
return firstKeyProp.Name;
}
case AcquiredEdmType.ColumnName:
{
// Find the storage property (column) that the property is mapped
edmInfo.PropertyColumnNameDic = edmInfo.PropertyColumnNameDic ?? new Dictionary<string, string>();
if (edmInfo.PropertyColumnNameDic.ContainsKey(propertyName))
{
return edmInfo.PropertyColumnNameDic[propertyName];
}
else
{
string columnName = edmInfo.Mapping
.EntityTypeMappings.Single()
.Fragments.Single()
.PropertyMappings
.OfType<ScalarPropertyMapping>()
.Single(m => m.Property.Name == propertyName)
.Column
.Name;
//写入缓存
edmInfo.PropertyColumnNameDic.Add(propertyName, columnName);
//实际上,下面的 if 判断肯定为 true,但为了避免后期改动了本方法最上面的代码,所以加一个判断。
if (_mappingCache.ContainsKey(type.FullName))
{
_mappingCache[type.FullName] = edmInfo;
}
else
{
_mappingCache.Add(type.FullName, edmInfo);
}
//return tableName + "." + columnName;
return columnName;
}
}
default:
throw new ArgumentNullException("Invalid argument");
}
} #endregion #region 额外方法 #endregion
}
}

Program.cs

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Core.Mapping;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.ModelConfiguration;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Linq;
using EntityFramework.Extensions;
using System.Linq.Expressions;
using EntityFrameworkSample; namespace EntityFrameworkSample
{
class Program
{
static void Main(string[] args)
{
using (var context = new BloggingContext(@"Data Source=.\SQLExpress;Initial Catalog=TestDB;Persist Security Info=True;User ID=sa;Password=123456"))
{
string blogTableName = context.GetTableName<Blog>();
string postTableName = context.GetTableName<Post>(); Console.WriteLine("Blog maps to: {0}", blogTableName);
Console.WriteLine("Post maps to: {0}", postTableName); string blogPrimaryKeyName = context.GetFirstPrimaryKeyName<Blog>();
string postPrimaryKeyName = context.GetFirstPrimaryKeyName<Post>(); Console.WriteLine("Blog primary key name: {0}", blogPrimaryKeyName);
Console.WriteLine("Post primary key name: {0}", postPrimaryKeyName); System.Diagnostics.Stopwatch watch = System.Diagnostics.Stopwatch.StartNew();
for (int i = ; i < ; i++)
{
context.GetColumnName<Blog, string>(c => c.BlogUrl); //经过测试,循环 60 万次,耗时 3.21 秒
}
watch.Stop();
Console.WriteLine("经过测试,循环 60 万次,耗时 {0} 秒", (watch.ElapsedMilliseconds / (double)).ToString("f2")); string blogUrlColumnName = context.GetColumnName<Blog, string>(c => c.BlogUrl);
string postTitleColumnName = context.GetColumnName<Post, string>(c => c.PostTitle); //Console.WriteLine("Blog.BlogUrl maps to: {0}.{1}", blogTableName, blogUrlColumnName);
Console.WriteLine("Post.PostTitle maps to: {0}.{1}", postTableName, postTitleColumnName); }
Console.ReadLine();
} } public class BloggingContext : DbContext
{
public BloggingContext(string nameOrConnectionString)
: base(nameOrConnectionString)
{ } public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new BlogMap());
modelBuilder.Configurations.Add(new PostMap());
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
base.OnModelCreating(modelBuilder);
}
} public class Blog
{
public int Id { get; set; }
public string BlogUrl { get; set; } public List<Post> Posts { get; set; }
} public class Post
{
public int Id { get; set; }
public string PostTitle { get; set; }
public string Body { get; set; } public int BlogId { get; set; }
public Blog Blog { get; set; }
} public class BlogMap : EntityTypeConfiguration<Blog>
{
public BlogMap()
{
this.HasKey(c => c.Id);
this.ToTable("t_blog");
this.Property(c => c.Id).HasColumnName("BlogId");
this.Property(c => c.BlogUrl).HasColumnName("Url");
}
} public class PostMap : EntityTypeConfiguration<Post>
{
public PostMap()
{
this.HasKey(c => c.Id);
this.ToTable("t_post");
this.Property(c => c.Id).HasColumnName("PostId");
this.Property(c => c.PostTitle).HasColumnName("Title");
}
}
}

运行截图:

小计:优化后,经过测试,从原来的 循环60万次,耗时14秒,降低到 循环60万次,耗时 3.21 秒。

谢谢浏览!

Entity Framework 6 中如何获取 EntityTypeConfiguration 的 Edm 信息?(四)的更多相关文章

  1. Entity Framework 6 中如何获取 EntityTypeConfiguration 的 Edm 信息?(一)

    1. 案例1 - 类型和表之间的EF代码优先映射 从EF6.1开始,有一种更简单的方法可以做到这一点.有关 详细信息,请参阅我的新EF6.1类型和表格之间的映射. 直接贴代码了 从EF6.1开始,有一 ...

  2. Entity Framework 6 中如何获取 EntityTypeConfiguration 的 Edm 信息?(五)

    直接贴代码了: NewsInfo 实体类: public class NewsInfo { public int NewsInfoId { get; set; } public string News ...

  3. Entity Framework 6 中如何获取 EntityTypeConfiguration 的 Edm 信息?(三)

    接着上一篇,我们继续来优化. 直接贴代码了: LambdaHelper.cs using System; using System.Collections.Generic; using System. ...

  4. Entity Framework 6 中如何获取 EntityTypeConfiguration 的 Edm 信息?(二)

    接着上一篇 直接贴代码了: using System; using System.Collections.Generic; using System.Data.Entity; using System ...

  5. 浅析Entity Framework Core中的并发处理

    前言 Entity Framework Core 2.0更新也已经有一段时间了,园子里也有不少的文章.. 本文主要是浅析一下Entity Framework Core的并发处理方式. 1.常见的并发处 ...

  6. 在Entity Framework 7中进行数据迁移

    (此文章同时发表在本人微信公众号“dotNET每日精华文章”,欢迎右边二维码来关注.) 题记:虽然EF7重新设计了Entity Framework,不过也还是能够支持数据迁移的. Entity Fra ...

  7. [Programming Entity Framework] 第3章 查询实体数据模型(EDM)(一)

    http://www.cnblogs.com/sansi/archive/2012/10/18/2729337.html Programming Entity Framework 第二版翻译索引 你可 ...

  8. 《Entity Framework 6 Recipes》中文翻译系列 (20) -----第四章 ASP.NET MVC中使用实体框架之在MVC中构建一个CRUD示例

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第四章  ASP.NET MVC中使用实体框架 ASP.NET是一个免费的Web框架 ...

  9. 《Entity Framework 6 Recipes》中文翻译系列 (21) -----第四章 ASP.NET MVC中使用实体框架之在页面中创建查询和使用ASP.NET URL路由过虑

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 4.2. 构建一个搜索查询 搜索数据是几乎所有应用的一个基本功能.它一般是动态的,因 ...

随机推荐

  1. Razor_02 第一个应用程序+Model+EF 添加

    第一个应用程序+Model+EF 添加 小试牛刀 今天 也试了试 边说边写,但是 有时候 编辑器不给力,或者网路不给力,倒是浪费大家时间,所以今天录制完了就裁切了 部分视频,如果有不清楚的地方,可以留 ...

  2. AQS(抽象队列同步器)

    AQS(全称为AbstractQueuedSynchronizer),即抽象队列同步器,它维护了一个volatile int state(代表共享资源)和一个FIFO线程等待队列. state的访问方 ...

  3. jQuery animate() 方法

    定义和用法 animate() 方法执行 CSS 属性集的自定义动画. 该方法通过 CSS 样式将元素从一个状态改变为另一个状态.CSS属性值是逐渐改变的,这样就可以创建动画效果. 只有数字值可创建动 ...

  4. Taro多端自定义导航栏Navbar+Tabbar实例

    运用Taro实现多端导航栏/tabbar实例 (H5 + 小程序 + React Native) 最近一直在捣鼓taro开发,虽说官网介绍支持编译到多端,但是网上大多数实例都是H5.小程序,很少有支持 ...

  5. 交互式shell脚本web console

    官网:http://web-console.org/ 这个脚本可以实现web下交互,也就是有了这玩意后可以不用反弹shell了. <?php // Web Console v0.9.7 (201 ...

  6. web网页利用JavaScript实现对摄像头的调用

    实现效果: 代码如下: <!DOCTYPE html> <html lang="zh"> <head> <meta charset=&qu ...

  7. https://jwt.io/一个可以解析token的神奇网站

    网址:https://jwt.io/ 效果:

  8. C学习笔记(1)---数据类型,变量,储存类

    1.常用基本数据类型占用空间(64位机器为例): char : 1个字节 -- int :4个字节 -- float:4个字节 -- double:8个字节 2.书写类型: A.整数: a. 默认为1 ...

  9. kettle教程---增量更新

    以下操作都在5.0.1版本下进行开发,其余版本可以进行自动比对 在平时工作当中,会遇到这种情况,而且很常见.比如:增量抽取(每隔2个小时抽取截至到上次抽取时间的记录) 一.操作前提: 存在3张表,源表 ...

  10. itest(爱测试) 3.3.5 发布,开源敏捷测试管理 & BUG 跟踪管理软件

    v3.3.5 下载地址 :itest下载 itest 简介:查看简介 V3.3.5 有 6个功能增强,2个BUG修复 ,详情如下所述. 用户反馈并强烈要求增强的功能实现:    1: 测试用例管理可线 ...