Entity Framework 6 中如何获取 EntityTypeConfiguration 的 Edm 信息?(四)
2018-09-26 18:53 音乐让我说 阅读(410) 评论(0) 编辑 收藏 举报经过上一篇,里面有测试代码,循环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[0]; //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 = 0; i < 600000; i++) { context.GetColumnName<Blog, string>(c => c.BlogUrl); //经过测试,循环 60 万次,耗时 3.21 秒 } watch.Stop(); Console.WriteLine("经过测试,循环 60 万次,耗时 {0} 秒", (watch.ElapsedMilliseconds / (double)1000).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 秒。
谢谢浏览!
作者:音乐让我说(音乐让我说 - 博客园)
出处:http://music.cnblogs.com/
文章版权归本人所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步