├── .gitignore ├── .nuget └── packages.config ├── Commands.txt ├── Dapper.EntityFramework.Extensions.nuspec ├── Dapper.EntityFramework.Extensions.sln ├── Dapper.EntityFramework.Extensions.v12.suo ├── Dapper.EntityFramework.Extensions ├── App.config ├── Dapper.EntityFramework.Extensions.csproj ├── Extensions.cs ├── Properties │ └── AssemblyInfo.cs └── packages.config ├── README.md └── Test ├── App.config ├── Models ├── Blog.cs ├── BlogPost.cs ├── BlogSettings.cs ├── Gender.cs ├── TestContext.Context.cs ├── TestContext.Context.tt ├── TestContext.Designer.cs ├── TestContext.cs ├── TestContext.edmx ├── TestContext.edmx.diagram ├── TestContext.tt ├── User.cs └── sysdiagram.cs ├── Program.cs ├── Properties └── AssemblyInfo.cs ├── Test.csproj └── packages.config /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | *.nupkg 4 | -------------------------------------------------------------------------------- /.nuget/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Commands.txt: -------------------------------------------------------------------------------- 1 | (*) GENERATE PACKAGE 2 | 3 | NuGet.exe pack .\Dapper.EntityFramework.Extensions.nuspec 4 | NuGet.exe pack .\Dapper.EntityFramework.Extensions.nuspec -Version 1.8.0.1 5 | NuGet.exe pack Dapper.EntityFramework.Extensions\Dapper.EntityFramework.Extensions.csproj -Build -Symbols -Properties Configuration=Release 6 | 7 | (*) PUSH PACKAGE 8 | NuGet.exe setapikey [APIKEY] 9 | NuGet.exe push Dapper.EntityFramework.Extensions.1.8.0.1.nupkg 10 | 11 | -------------------------------------------------------------------------------- /Dapper.EntityFramework.Extensions.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Dapper.EntityFramework.Extensions 5 | 1.8.0.1 6 | Dapper entity framework extensions 7 | Thiago Amarante 8 | Thiago Amarante 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | https://github.com/thiagoamarante/Dapper.EntityFramework.Extensions 11 | false 12 | 13 | Extension for EntityFramework 14 | Library brings together the best of the EntityFramework with Dapper. 15 | Basic CRUD operations (Query, Insert, Update, Delete) for your POCOs. 16 | 17 | Adds support for methods dapper in DbSet and Crud 18 | orm sql micro-orm entityframework entity framework extensions 19 | http://go.microsoft.com/fwlink/?LinkID=386613 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | (*) Release 1.8.0.1 33 | - Support DbGeography/DbGeometry 34 | 35 | (*) Release 1.7.0.1 36 | - Insert optional return identity 37 | - Insert return identity object type 38 | - Insert and Update can change PropertyKey 39 | - Insert and Update automatic removes property of different kind of primitive and enum 40 | 41 | (*) Release 1.7.0.0 42 | - New method Query and Query with selector 43 | - Query support top 44 | - Query support where 45 | - Query support orderby 46 | - Query support selector 47 | 48 | (*) Release 1.6.0.1 49 | - Support schemas 50 | - Support EntityFramework in Transaction 51 | - Support CommandTimeout DbContext 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /Dapper.EntityFramework.Extensions.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapper.EntityFramework.Extensions", "Dapper.EntityFramework.Extensions\Dapper.EntityFramework.Extensions.csproj", "{D10801FF-2C63-4180-BFD9-A92BFCF9E2F8}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6D0D1E42-C01E-45B1-A437-26B1C8FF3906}" 9 | ProjectSection(SolutionItems) = preProject 10 | Commands.txt = Commands.txt 11 | Dapper.EntityFramework.Extensions.nuspec = Dapper.EntityFramework.Extensions.nuspec 12 | README.md = README.md 13 | EndProjectSection 14 | EndProject 15 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{8F8C8CB9-4281-469F-AE49-B197AC64CD23}" 16 | ProjectSection(SolutionItems) = preProject 17 | .nuget\packages.config = .nuget\packages.config 18 | EndProjectSection 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{65A076AA-3E50-4A39-AAAB-16CCC9BE694E}" 21 | EndProject 22 | Global 23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 24 | Debug|Any CPU = Debug|Any CPU 25 | Release|Any CPU = Release|Any CPU 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {D10801FF-2C63-4180-BFD9-A92BFCF9E2F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {D10801FF-2C63-4180-BFD9-A92BFCF9E2F8}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {D10801FF-2C63-4180-BFD9-A92BFCF9E2F8}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {D10801FF-2C63-4180-BFD9-A92BFCF9E2F8}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {65A076AA-3E50-4A39-AAAB-16CCC9BE694E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {65A076AA-3E50-4A39-AAAB-16CCC9BE694E}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {65A076AA-3E50-4A39-AAAB-16CCC9BE694E}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {65A076AA-3E50-4A39-AAAB-16CCC9BE694E}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | EndGlobal 41 | -------------------------------------------------------------------------------- /Dapper.EntityFramework.Extensions.v12.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thiagoamarante/Dapper.EntityFramework.Extensions/543da01abfe01ea2d1b9e6935f79db2e721c75b4/Dapper.EntityFramework.Extensions.v12.suo -------------------------------------------------------------------------------- /Dapper.EntityFramework.Extensions/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Dapper.EntityFramework.Extensions/Dapper.EntityFramework.Extensions.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {D10801FF-2C63-4180-BFD9-A92BFCF9E2F8} 8 | Library 9 | Properties 10 | Dapper.EntityFramework.Extensions 11 | Dapper.EntityFramework.Extensions 12 | v4.5 13 | 512 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | true 25 | full 26 | false 27 | bin\Debug\ 28 | DEBUG;TRACE 29 | prompt 30 | 4 31 | 32 | 33 | pdbonly 34 | true 35 | bin\Release\ 36 | TRACE 37 | prompt 38 | 4 39 | 40 | 41 | 42 | ..\..\..\..\Packages\Dapper.1.42\lib\net45\Dapper.dll 43 | True 44 | 45 | 46 | ..\..\..\..\Packages\Dapper.EntityFramework.1.33\lib\net45\Dapper.EntityFramework.dll 47 | True 48 | 49 | 50 | ..\..\..\..\Packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll 51 | True 52 | 53 | 54 | ..\..\..\..\Packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll 55 | True 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 82 | -------------------------------------------------------------------------------- /Dapper.EntityFramework.Extensions/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Entity; 4 | using System.Data.Entity.Core.Objects; 5 | using System.Data.Entity.Infrastructure; 6 | using System.Linq; 7 | using System.Linq.Expressions; 8 | using System.Reflection; 9 | using Dapper; 10 | using System.Dynamic; 11 | using System.Collections.Concurrent; 12 | using System.Reflection.Emit; 13 | using System.Threading; 14 | using System.Diagnostics; 15 | using System.Collections; 16 | using System.Data.Entity.Core.Metadata.Edm; 17 | 18 | namespace Dapper 19 | { 20 | public static class Extensions 21 | { 22 | private static bool _Init = false; 23 | private static Dictionary _CacheTable = new Dictionary(); 24 | private static string[] AcceptTypes = new string[] { "System.Data.Entity.Spatial.DbGeometry", "System.Data.Entity.Spatial.DbGeography" }; 25 | 26 | #region Methods 27 | public static object Insert(this DbSet source, object entity, bool returnIdentity = true, string propertyKey = "Id") 28 | where TEntity : class 29 | { 30 | Init(); 31 | #if DEBUG 32 | var watch = LogStart("INSERT"); 33 | #endif 34 | var context = source.GetDbContext(); 35 | #if DEBUG 36 | LogElapsed(watch, "GetDbContext"); 37 | #endif 38 | 39 | string table = GetTableName(context); 40 | string[] properties = entity.GetType().GetProperties().Where(o => (o.PropertyType.IsEnum || AcceptTypes.Contains(o.PropertyType.FullName) || Type.GetTypeCode(o.PropertyType) != TypeCode.Object) && o.Name != propertyKey).Select(o => o.Name).ToArray(); 41 | string sql = string.Concat("INSERT INTO ", table, " (", 42 | string.Join(", ", properties.Select(o => string.Concat("[", o, "]"))), 43 | ") VALUES(", 44 | string.Join(", ", properties.Select(o => "@" + o)), ");"); 45 | 46 | if (returnIdentity) 47 | sql += " SELECT SCOPE_IDENTITY()"; 48 | 49 | #if DEBUG 50 | LogElapsed(watch, "Parse"); 51 | #endif 52 | var result = context.Database.Connection.ExecuteScalar(sql, entity, transaction: context.Database.CurrentTransaction != null ? context.Database.CurrentTransaction.UnderlyingTransaction : null, commandTimeout: context.Database.CommandTimeout); 53 | #if DEBUG 54 | LogElapsed(watch, "Execution"); 55 | #endif 56 | if (returnIdentity && result != null) 57 | { 58 | var propertyId = entity.GetType().GetProperty(propertyKey); 59 | if (propertyId != null && propertyId.CanWrite) 60 | propertyId.SetValue(entity, Convert.ChangeType(result, propertyId.PropertyType)); 61 | } 62 | return result; 63 | } 64 | 65 | public static int Update(this DbSet source, object entity, Expression> where = null, string propertyKey = "Id") 66 | where TEntity : class 67 | { 68 | Init(); 69 | #if DEBUG 70 | var watch = LogStart("UPDATE"); 71 | #endif 72 | var context = source.GetDbContext(); 73 | #if DEBUG 74 | LogElapsed(watch, "GetDbContext"); 75 | #endif 76 | DynamicParameters parameter = new DynamicParameters(); 77 | parameter.AddDynamicParams(entity); 78 | string table = GetTableName(context); 79 | Dictionary properties = entity.GetType().GetProperties().ToDictionary(o => o.Name, o => o.PropertyType); 80 | string sql = string.Concat("UPDATE ", table, " SET ", 81 | string.Join(", ", properties.Where(o => (o.Value.IsEnum || AcceptTypes.Contains(o.Value.FullName) || Type.GetTypeCode(o.Value) != TypeCode.Object) && o.Key != propertyKey).Select(o => string.Concat("[", o.Key, "]") + " = @" + o.Key))); 82 | #if DEBUG 83 | LogElapsed(watch, "Parse update"); 84 | #endif 85 | if (where != null) 86 | { 87 | sql += " " + ProcessWhere(parameter, source, where); 88 | #if DEBUG 89 | LogElapsed(watch, "Parse where"); 90 | #endif 91 | } 92 | else if (properties.Any(o => o.Key == propertyKey)) 93 | sql += string.Concat(" WHERE [", propertyKey, "] = @Id"); 94 | var result = context.Database.Connection.Execute(sql, parameter, transaction: context.Database.CurrentTransaction != null? context.Database.CurrentTransaction.UnderlyingTransaction : null, commandTimeout: context.Database.CommandTimeout); 95 | #if DEBUG 96 | LogElapsed(watch, "Execution"); 97 | #endif 98 | return result; 99 | } 100 | 101 | public static int Delete(this DbSet source, Expression> where = null) 102 | where TEntity : class 103 | { 104 | Init(); 105 | #if DEBUG 106 | var watch = LogStart("DELETE"); 107 | #endif 108 | var context = source.GetDbContext(); 109 | #if DEBUG 110 | LogElapsed(watch, "GetDbContext"); 111 | #endif 112 | DynamicParameters parameter = new DynamicParameters(); 113 | string table = GetTableName(context); 114 | string sql = string.Concat("DELETE FROM ", table, ""); 115 | #if DEBUG 116 | LogElapsed(watch, "Parse"); 117 | #endif 118 | if (where != null) 119 | { 120 | sql += " " + ProcessWhere(parameter, source, where); 121 | #if DEBUG 122 | LogElapsed(watch, "Parse where"); 123 | #endif 124 | } 125 | var result = context.Database.Connection.Execute(sql, parameter, transaction: context.Database.CurrentTransaction != null ? context.Database.CurrentTransaction.UnderlyingTransaction : null, commandTimeout: context.Database.CommandTimeout); 126 | #if DEBUG 127 | LogElapsed(watch, "Execution"); 128 | #endif 129 | return result; 130 | } 131 | 132 | public static IEnumerable Query(this DbSet source, Expression> where = null, int? top = null, Func, OrderBy> orderBy = null) 133 | where TEntity : class 134 | { 135 | Init(); 136 | #if DEBUG 137 | var watch = LogStart("QUERY"); 138 | #endif 139 | var context = source.GetDbContext(); 140 | #if DEBUG 141 | LogElapsed(watch, "GetDbContext"); 142 | #endif 143 | 144 | var objectQuery = (ObjectQuery)((IObjectContextAdapter)context).ObjectContext.CreateObjectSet(); 145 | if (where != null) 146 | objectQuery = (ObjectQuery)objectQuery.Where(where); 147 | 148 | if (orderBy != null) 149 | { 150 | OrderBy order = new OrderBy(objectQuery); 151 | orderBy(order); 152 | objectQuery = order.Query; 153 | } 154 | 155 | string query = objectQuery.ToTraceString(); 156 | 157 | DynamicParameters parameters = new DynamicParameters(); 158 | foreach (var param in objectQuery.Parameters) 159 | parameters.Add("@" + param.Name, param.Value); 160 | 161 | if (top != null) 162 | { 163 | query = "SELECT TOP " + top.Value + query.Substring(query.IndexOf("SELECT") + 6); 164 | } 165 | #if DEBUG 166 | LogElapsed(watch, "Parse"); 167 | #endif 168 | var result = context.Database.Connection.Query(query, parameters, transaction: context.Database.CurrentTransaction != null ? context.Database.CurrentTransaction.UnderlyingTransaction : null, commandTimeout: context.Database.CommandTimeout); 169 | #if DEBUG 170 | LogElapsed(watch, "Execution"); 171 | #endif 172 | return result; 173 | } 174 | 175 | public static IEnumerable Query(this DbSet source, Expression> selector, Expression> where = null, int? top = null, Func, OrderBy> orderBy = null) 176 | where TEntity : class 177 | where TResult : class 178 | { 179 | Init(); 180 | #if DEBUG 181 | var watch = LogStart("QUERY WITH SELECTOR"); 182 | #endif 183 | var context = source.GetDbContext(); 184 | #if DEBUG 185 | LogElapsed(watch, "GetDbContext"); 186 | #endif 187 | 188 | var objectQuery = (ObjectQuery)((IObjectContextAdapter)context).ObjectContext.CreateObjectSet(); 189 | if (where != null) 190 | objectQuery = (ObjectQuery)objectQuery.Where(where); 191 | 192 | var objectQuerySelector = (ObjectQuery)objectQuery.Select(selector); 193 | 194 | if (orderBy != null) 195 | { 196 | OrderBy order = new OrderBy(objectQuerySelector); 197 | orderBy(order); 198 | objectQuerySelector = order.Query; 199 | } 200 | 201 | string query = objectQuerySelector.ToTraceString(); 202 | 203 | DynamicParameters parameters = new DynamicParameters(); 204 | foreach (var param in objectQuery.Parameters) 205 | parameters.Add("@" + param.Name, param.Value); 206 | 207 | if (top != null) 208 | { 209 | query = "SELECT TOP " + top.Value + query.Substring(query.IndexOf("SELECT") + 6); 210 | } 211 | #if DEBUG 212 | LogElapsed(watch, "Parse"); 213 | #endif 214 | var result = context.Database.Connection.Query(query, parameters, transaction: context.Database.CurrentTransaction != null ? context.Database.CurrentTransaction.UnderlyingTransaction : null, commandTimeout: context.Database.CommandTimeout); 215 | #if DEBUG 216 | LogElapsed(watch, "Execution"); 217 | #endif 218 | return result; 219 | } 220 | 221 | public static IEnumerable ToDapper(this IQueryable source) 222 | where TEntity : class 223 | { 224 | Init(); 225 | #if DEBUG 226 | var watch = LogStart("ToDapper"); 227 | #endif 228 | var context = source.GetDbContext(); 229 | #if DEBUG 230 | LogElapsed(watch, "GetDbContext"); 231 | #endif 232 | string query = source.ToString(); 233 | #if DEBUG 234 | LogElapsed(watch, "Parse"); 235 | #endif 236 | var result = context.Database.Connection.Query(query); 237 | #if DEBUG 238 | LogElapsed(watch, "Execution"); 239 | #endif 240 | return result; 241 | } 242 | 243 | public static void Initialize(this DbContext context) 244 | { 245 | #if DEBUG 246 | var watch = LogStart("Initialize"); 247 | #endif 248 | context.Database.Initialize(true); 249 | #if DEBUG 250 | LogElapsed(watch, "Database.Initialize"); 251 | #endif 252 | foreach (var property in context.GetType().GetProperties().Where(o => o.PropertyType.Name == "DbSet`1")) 253 | { 254 | var dbSet = property.GetValue(context); 255 | dbSet.ToString(); 256 | } 257 | #if DEBUG 258 | LogElapsed(watch, "Cache DbSet"); 259 | #endif 260 | } 261 | 262 | public static void Optimization(this DbContext context) 263 | { 264 | context.Configuration.AutoDetectChangesEnabled = false; 265 | context.Configuration.LazyLoadingEnabled = false; 266 | context.Configuration.ProxyCreationEnabled = false; 267 | context.Configuration.ValidateOnSaveEnabled = false; 268 | } 269 | #endregion 270 | 271 | #region Methods Private 272 | 273 | private static DbContext GetDbContext(this IQueryable source) 274 | { 275 | var internalContextProperty = source.Provider.GetType().GetProperty("InternalContext"); 276 | if(internalContextProperty != null) 277 | { 278 | var internalContext = internalContextProperty.GetValue(source.Provider); 279 | var ownerProperty = internalContext.GetType().GetProperty("Owner", BindingFlags.Instance | BindingFlags.Public); 280 | if (ownerProperty != null) 281 | { 282 | DbContext dbContext = (DbContext)ownerProperty.GetValue(internalContext, null); 283 | if (dbContext != null) 284 | return dbContext; 285 | else 286 | throw new Exception("Context not found"); 287 | } 288 | else 289 | throw new Exception("Owner not found"); 290 | } 291 | else 292 | throw new Exception("InternalContext not found"); 293 | } 294 | 295 | private static string ProcessWhere(DynamicParameters parameters, DbSet source, System.Linq.Expressions.Expression> where) 296 | where TEntity : class 297 | { 298 | var context = source.GetDbContext(); 299 | var objectQuery = ((ObjectQuery)((IObjectContextAdapter)context).ObjectContext.CreateObjectSet().Where(where)); 300 | string query = objectQuery.ToTraceString(); 301 | foreach(var param in objectQuery.Parameters) 302 | parameters.Add("@" + param.Name, param.Value); 303 | return query.Substring(query.IndexOf("WHERE")).Replace("[Extent1].", ""); 304 | } 305 | 306 | private static string GetTableName(DbContext context) 307 | where TEntity : class 308 | { 309 | Type type = typeof(TEntity); 310 | if (!_CacheTable.ContainsKey(type)) 311 | { 312 | var objectContext = (context as IObjectContextAdapter).ObjectContext; 313 | var metadata = ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace; 314 | EntitySet entitySet = metadata.GetItemCollection(DataSpace.SSpace) 315 | .GetItems() 316 | .Single() 317 | .BaseEntitySets 318 | .OfType() 319 | .FirstOrDefault(s => (!s.MetadataProperties.Contains("Type") 320 | || s.MetadataProperties["Type"].ToString() == "Tables") && s.Name == type.Name); 321 | 322 | if (entitySet == null) 323 | throw new Exception(string.Format("entitySet ({0}) not found", type.Name)); 324 | 325 | _CacheTable.Add(type, string.Format("[{0}].[{1}]", entitySet.Schema, entitySet.Name)); 326 | } 327 | return _CacheTable[type]; 328 | } 329 | 330 | private static void Init() 331 | { 332 | if (!_Init) 333 | { 334 | _Init = true; 335 | Dapper.EntityFramework.Handlers.Register(); 336 | } 337 | } 338 | #endregion 339 | 340 | #if DEBUG 341 | private static Stopwatch LogStart(string message) 342 | { 343 | Console.WriteLine(message); 344 | var watch = new Stopwatch(); 345 | watch.Start(); 346 | return watch; 347 | } 348 | 349 | private static void LogElapsed(Stopwatch watch, string message) 350 | { 351 | Console.WriteLine(watch.ElapsedMilliseconds + "ms - " + message); 352 | watch.Restart(); 353 | } 354 | #endif 355 | } 356 | 357 | #region Class 358 | public class OrderBy 359 | where TEntity : class 360 | { 361 | private int _Orders = 0; 362 | public OrderBy(ObjectQuery query) 363 | { 364 | this.Query = query; 365 | } 366 | 367 | public ObjectQuery Query { get; private set; } 368 | 369 | public OrderBy Asc(Expression> keySelector) 370 | { 371 | if (_Orders > 0) 372 | this.Query = (ObjectQuery)this.Query.ThenBy(keySelector); 373 | else 374 | this.Query = (ObjectQuery)this.Query.OrderBy(keySelector); 375 | _Orders++; 376 | return this; 377 | } 378 | 379 | public OrderBy Desc(Expression> keySelector) 380 | { 381 | if (_Orders > 0) 382 | this.Query = (ObjectQuery)this.Query.ThenByDescending(keySelector); 383 | else 384 | this.Query = (ObjectQuery)this.Query.OrderByDescending(keySelector); 385 | _Orders++; 386 | return this; 387 | } 388 | } 389 | 390 | 391 | #endregion 392 | } 393 | -------------------------------------------------------------------------------- /Dapper.EntityFramework.Extensions/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Dapper.EntityFramework.Extensions")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Dapper.EntityFramework.Extensions")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("6c6a610f-5785-48b8-8614-b862544f6b7f")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.8.0.1")] 36 | [assembly: AssemblyFileVersion("1.8.0.1")] 37 | -------------------------------------------------------------------------------- /Dapper.EntityFramework.Extensions/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dapper.EntityFramework.Extensions (1.8.0.1) 2 | Extension for EntityFramework 3 | Library brings together the best of the EntityFramework with Dapper. 4 | Basic CRUD operations (Query, Insert, Update, Delete) for your POCOs. 5 | 6 | (*) Release 1.8.0.1 7 | - Support DbGeography/DbGeometry 8 | 9 | (*) Release 1.7.0.1 10 | - Insert optional return identity 11 | - Insert return identity object type 12 | - Insert and Update can change PropertyKey 13 | - Insert and Update automatic removes property of different kind of primitive and enum 14 | 15 | (*) Release 1.7.0.0 16 | - New method Query and Query with selector 17 | - Query support top 18 | - Query support where 19 | - Query support orderby 20 | - Query support selector 21 | 22 | (*) Release 1.6.0.1 23 | - Support schemas 24 | - Support EntityFramework in Transaction 25 | - Support CommandTimeout DbContext 26 | 27 | using Dapper; 28 | 29 | public class Example 30 | { 31 | 32 | public static void Insert() 33 | { 34 | using (TestEntities context = new TestEntities()) 35 | { 36 | var obj = new 37 | { 38 | Name = "User Insert", 39 | DateCreate = DateTime.Now, 40 | Gender = Gender.Female 41 | }; 42 | watch.Restart(); 43 | context.Users.Insert(obj); 44 | Console.WriteLine("Insert With Anonymous - {0}ms", watch.ElapsedMilliseconds); 45 | 46 | Console.WriteLine(); 47 | watch.Restart(); 48 | var obj2 = new User() 49 | { 50 | Name = "User Insert", 51 | DateCreate = DateTime.Now, 52 | Gender = Gender.Male 53 | }; 54 | context.Users.Insert(obj2); 55 | Console.WriteLine("Insert With Class - {0}ms", watch.ElapsedMilliseconds); 56 | 57 | Console.WriteLine(); 58 | watch.Restart(); 59 | context.Users.Insert(obj, returnIdentity: false); 60 | Console.WriteLine("Insert Without Return Identity - {0}ms", watch.ElapsedMilliseconds); 61 | 62 | Console.WriteLine(); 63 | watch.Restart(); 64 | context.Users.Insert(obj, propertyKey: "User_Id"); 65 | Console.WriteLine("Insert With Change PropertyKey - {0}ms", watch.ElapsedMilliseconds); 66 | } 67 | Console.WriteLine(); 68 | } 69 | 70 | public static void Update() 71 | { 72 | using (TestEntities context = new TestEntities()) 73 | { 74 | var obj = new 75 | { 76 | Gender = Gender.Male 77 | }; 78 | 79 | watch.Restart(); 80 | context.Users.Update(obj); 81 | Console.WriteLine("Update All - {0}ms", watch.ElapsedMilliseconds); 82 | 83 | Console.WriteLine(); 84 | watch.Restart(); 85 | context.Users.Update(new 86 | { 87 | Gender = Gender.Female 88 | }, o=> o.Id == 1); 89 | Console.WriteLine("Update With Query - {0}ms", watch.ElapsedMilliseconds); 90 | 91 | Console.WriteLine(); 92 | watch.Restart(); 93 | context.Users.Update(new 94 | { 95 | Gender = Gender.Female 96 | }, o => o.Id == 1 && (o.Name == "teste" || o.DateCreate > DateTime.Now)); 97 | Console.WriteLine("Update With Complex Query - {0}ms", watch.ElapsedMilliseconds); 98 | } 99 | Console.WriteLine(); 100 | } 101 | 102 | public static void Delete() 103 | { 104 | using (TestEntities context = new TestEntities()) 105 | { 106 | watch.Restart(); 107 | context.BlogPosts.Delete(); 108 | Console.WriteLine("Delete All - {0}ms", watch.ElapsedMilliseconds); 109 | 110 | Console.WriteLine(); 111 | watch.Restart(); 112 | context.Users.Delete(o => o.Id == 6); 113 | Console.WriteLine("Delete With Query - {0}ms", watch.ElapsedMilliseconds); 114 | } 115 | Console.WriteLine(); 116 | } 117 | 118 | public static void Select() 119 | { 120 | using (TestEntities context = new TestEntities()) 121 | { 122 | watch.Restart(); 123 | var result = context.Users.Query(o => o.Id > 1, 2, orderBy => orderBy.Asc(o => o.Id ).Desc(o => o.Name)); 124 | int qtd = result.Count(); 125 | Console.WriteLine("Select - {0}ms", watch.ElapsedMilliseconds); 126 | 127 | watch.Restart(); 128 | var result2 = context.Users.Query(o=> new { o.Id, o.Name }, o => o.Id > 1, 2, orderBy => orderBy.Asc(o => o.Id).Desc(o => o.Name)); 129 | qtd = result2.Count(); 130 | Console.WriteLine("Select With Selector - {0}ms", watch.ElapsedMilliseconds); 131 | } 132 | Console.WriteLine(); 133 | } 134 | 135 | public static void ToDapper() 136 | { 137 | using(TestEntities context = new TestEntities()) 138 | { 139 | object result = null; 140 | watch.Restart(); 141 | result = (from o in context.Users 142 | where o.Id > 1 143 | orderby o.Id 144 | select o).ToDapper().ToList(); 145 | Console.WriteLine("ToDapper - {0}ms", watch.ElapsedMilliseconds); 146 | } 147 | } 148 | 149 | public static void Transaction() 150 | { 151 | using(TestEntities context = new TestEntities()) 152 | { 153 | using (var transaction = context.Database.BeginTransaction()) 154 | { 155 | try 156 | { 157 | repository.BlogPosts.Delete(); 158 | repository.Blogs.Delete(); 159 | transaction.Commit(); 160 | } 161 | catch(Exception ex) 162 | { 163 | transaction.Rollback(); 164 | } 165 | } 166 | } 167 | } 168 | 169 | public static void EntityFrameworkAndDapperTogether() 170 | { 171 | using(TestEntities context = new TestEntities()) 172 | { 173 | using (var transaction = context.Database.BeginTransaction()) 174 | { 175 | try 176 | { 177 | repository.BlogPosts.Add(new BlogPost() 178 | { 179 | BlogId = 1, 180 | Body = "text body", 181 | DatePublication = DateTime.Now 182 | }); 183 | repository.SaveChanges(); 184 | 185 | repository.BlogSettings.Update(new { AutoSave = true}, o=> o.BlogId = 1); 186 | 187 | transaction.Commit(); 188 | } 189 | catch(Exception ex) 190 | { 191 | transaction.Rollback(); 192 | } 193 | } 194 | } 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /Test/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Test/Models/Blog.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated from a template. 4 | // 5 | // Manual changes to this file may cause unexpected behavior in your application. 6 | // Manual changes to this file will be overwritten if the code is regenerated. 7 | // 8 | //------------------------------------------------------------------------------ 9 | 10 | namespace Test.Models 11 | { 12 | using System; 13 | using System.Collections.Generic; 14 | 15 | public partial class Blog 16 | { 17 | public Blog() 18 | { 19 | this.BlogPosts = new HashSet(); 20 | } 21 | 22 | public int Id { get; set; } 23 | public int UserId { get; set; } 24 | public string Name { get; set; } 25 | public System.DateTime DateCreate { get; set; } 26 | public string Description { get; set; } 27 | 28 | public virtual User User { get; set; } 29 | public virtual ICollection BlogPosts { get; set; } 30 | public virtual BlogSettings BlogSettings { get; set; } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Test/Models/BlogPost.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated from a template. 4 | // 5 | // Manual changes to this file may cause unexpected behavior in your application. 6 | // Manual changes to this file will be overwritten if the code is regenerated. 7 | // 8 | //------------------------------------------------------------------------------ 9 | 10 | namespace Test.Models 11 | { 12 | using System; 13 | using System.Collections.Generic; 14 | 15 | public partial class BlogPost 16 | { 17 | public int Id { get; set; } 18 | public int BlogId { get; set; } 19 | public string Body { get; set; } 20 | public System.DateTime DatePublication { get; set; } 21 | 22 | public virtual Blog Blog { get; set; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Test/Models/BlogSettings.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated from a template. 4 | // 5 | // Manual changes to this file may cause unexpected behavior in your application. 6 | // Manual changes to this file will be overwritten if the code is regenerated. 7 | // 8 | //------------------------------------------------------------------------------ 9 | 10 | namespace Test.Models 11 | { 12 | using System; 13 | using System.Collections.Generic; 14 | 15 | public partial class BlogSettings 16 | { 17 | public int BlogId { get; set; } 18 | public bool AutoSave { get; set; } 19 | public bool AutoPost { get; set; } 20 | 21 | public virtual Blog Blog { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Test/Models/Gender.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Test.Models 8 | { 9 | public enum Gender 10 | { 11 | Male = 0, 12 | Female = 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Test/Models/TestContext.Context.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated from a template. 4 | // 5 | // Manual changes to this file may cause unexpected behavior in your application. 6 | // Manual changes to this file will be overwritten if the code is regenerated. 7 | // 8 | //------------------------------------------------------------------------------ 9 | 10 | namespace Test.Models 11 | { 12 | using System; 13 | using System.Data.Entity; 14 | using System.Data.Entity.Infrastructure; 15 | 16 | public partial class TestEntities : DbContext 17 | { 18 | public TestEntities() 19 | : base("name=TestEntities") 20 | { 21 | } 22 | 23 | protected override void OnModelCreating(DbModelBuilder modelBuilder) 24 | { 25 | throw new UnintentionalCodeFirstException(); 26 | } 27 | 28 | public virtual DbSet Blogs { get; set; } 29 | public virtual DbSet BlogPosts { get; set; } 30 | public virtual DbSet BlogSettings1 { get; set; } 31 | public virtual DbSet sysdiagrams { get; set; } 32 | public virtual DbSet Users { get; set; } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Test/Models/TestContext.Context.tt: -------------------------------------------------------------------------------- 1 | <#@ template language="C#" debug="false" hostspecific="true"#> 2 | <#@ include file="EF6.Utility.CS.ttinclude"#><#@ 3 | output extension=".cs"#><# 4 | 5 | const string inputFile = @"TestContext.edmx"; 6 | var textTransform = DynamicTextTransformation.Create(this); 7 | var code = new CodeGenerationTools(this); 8 | var ef = new MetadataTools(this); 9 | var typeMapper = new TypeMapper(code, ef, textTransform.Errors); 10 | var loader = new EdmMetadataLoader(textTransform.Host, textTransform.Errors); 11 | var itemCollection = loader.CreateEdmItemCollection(inputFile); 12 | var modelNamespace = loader.GetModelNamespace(inputFile); 13 | var codeStringGenerator = new CodeStringGenerator(code, typeMapper, ef); 14 | 15 | var container = itemCollection.OfType().FirstOrDefault(); 16 | if (container == null) 17 | { 18 | return string.Empty; 19 | } 20 | #> 21 | //------------------------------------------------------------------------------ 22 | // 23 | // <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine1")#> 24 | // 25 | // <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine2")#> 26 | // <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine3")#> 27 | // 28 | //------------------------------------------------------------------------------ 29 | 30 | <# 31 | 32 | var codeNamespace = code.VsNamespaceSuggestion(); 33 | if (!String.IsNullOrEmpty(codeNamespace)) 34 | { 35 | #> 36 | namespace <#=code.EscapeNamespace(codeNamespace)#> 37 | { 38 | <# 39 | PushIndent(" "); 40 | } 41 | 42 | #> 43 | using System; 44 | using System.Data.Entity; 45 | using System.Data.Entity.Infrastructure; 46 | <# 47 | if (container.FunctionImports.Any()) 48 | { 49 | #> 50 | using System.Data.Entity.Core.Objects; 51 | using System.Linq; 52 | <# 53 | } 54 | #> 55 | 56 | <#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext 57 | { 58 | public <#=code.Escape(container)#>() 59 | : base("name=<#=container.Name#>") 60 | { 61 | <# 62 | if (!loader.IsLazyLoadingEnabled(container)) 63 | { 64 | #> 65 | this.Configuration.LazyLoadingEnabled = false; 66 | <# 67 | } 68 | 69 | foreach (var entitySet in container.BaseEntitySets.OfType()) 70 | { 71 | // Note: the DbSet members are defined below such that the getter and 72 | // setter always have the same accessibility as the DbSet definition 73 | if (Accessibility.ForReadOnlyProperty(entitySet) != "public") 74 | { 75 | #> 76 | <#=codeStringGenerator.DbSetInitializer(entitySet)#> 77 | <# 78 | } 79 | } 80 | #> 81 | } 82 | 83 | protected override void OnModelCreating(DbModelBuilder modelBuilder) 84 | { 85 | throw new UnintentionalCodeFirstException(); 86 | } 87 | 88 | <# 89 | foreach (var entitySet in container.BaseEntitySets.OfType()) 90 | { 91 | #> 92 | <#=codeStringGenerator.DbSet(entitySet)#> 93 | <# 94 | } 95 | 96 | foreach (var edmFunction in container.FunctionImports) 97 | { 98 | WriteFunctionImport(typeMapper, codeStringGenerator, edmFunction, modelNamespace, includeMergeOption: false); 99 | } 100 | #> 101 | } 102 | <# 103 | 104 | if (!String.IsNullOrEmpty(codeNamespace)) 105 | { 106 | PopIndent(); 107 | #> 108 | } 109 | <# 110 | } 111 | #> 112 | <#+ 113 | 114 | private void WriteFunctionImport(TypeMapper typeMapper, CodeStringGenerator codeStringGenerator, EdmFunction edmFunction, string modelNamespace, bool includeMergeOption) 115 | { 116 | if (typeMapper.IsComposable(edmFunction)) 117 | { 118 | #> 119 | 120 | [DbFunction("<#=edmFunction.NamespaceName#>", "<#=edmFunction.Name#>")] 121 | <#=codeStringGenerator.ComposableFunctionMethod(edmFunction, modelNamespace)#> 122 | { 123 | <#+ 124 | codeStringGenerator.WriteFunctionParameters(edmFunction, WriteFunctionParameter); 125 | #> 126 | <#=codeStringGenerator.ComposableCreateQuery(edmFunction, modelNamespace)#> 127 | } 128 | <#+ 129 | } 130 | else 131 | { 132 | #> 133 | 134 | <#=codeStringGenerator.FunctionMethod(edmFunction, modelNamespace, includeMergeOption)#> 135 | { 136 | <#+ 137 | codeStringGenerator.WriteFunctionParameters(edmFunction, WriteFunctionParameter); 138 | #> 139 | <#=codeStringGenerator.ExecuteFunction(edmFunction, modelNamespace, includeMergeOption)#> 140 | } 141 | <#+ 142 | if (typeMapper.GenerateMergeOptionFunction(edmFunction, includeMergeOption)) 143 | { 144 | WriteFunctionImport(typeMapper, codeStringGenerator, edmFunction, modelNamespace, includeMergeOption: true); 145 | } 146 | } 147 | } 148 | 149 | public void WriteFunctionParameter(string name, string isNotNull, string notNullInit, string nullInit) 150 | { 151 | #> 152 | var <#=name#> = <#=isNotNull#> ? 153 | <#=notNullInit#> : 154 | <#=nullInit#>; 155 | 156 | <#+ 157 | } 158 | 159 | public const string TemplateId = "CSharp_DbContext_Context_EF6"; 160 | 161 | public class CodeStringGenerator 162 | { 163 | private readonly CodeGenerationTools _code; 164 | private readonly TypeMapper _typeMapper; 165 | private readonly MetadataTools _ef; 166 | 167 | public CodeStringGenerator(CodeGenerationTools code, TypeMapper typeMapper, MetadataTools ef) 168 | { 169 | ArgumentNotNull(code, "code"); 170 | ArgumentNotNull(typeMapper, "typeMapper"); 171 | ArgumentNotNull(ef, "ef"); 172 | 173 | _code = code; 174 | _typeMapper = typeMapper; 175 | _ef = ef; 176 | } 177 | 178 | public string Property(EdmProperty edmProperty) 179 | { 180 | return string.Format( 181 | CultureInfo.InvariantCulture, 182 | "{0} {1} {2} {{ {3}get; {4}set; }}", 183 | Accessibility.ForProperty(edmProperty), 184 | _typeMapper.GetTypeName(edmProperty.TypeUsage), 185 | _code.Escape(edmProperty), 186 | _code.SpaceAfter(Accessibility.ForGetter(edmProperty)), 187 | _code.SpaceAfter(Accessibility.ForSetter(edmProperty))); 188 | } 189 | 190 | public string NavigationProperty(NavigationProperty navProp) 191 | { 192 | var endType = _typeMapper.GetTypeName(navProp.ToEndMember.GetEntityType()); 193 | return string.Format( 194 | CultureInfo.InvariantCulture, 195 | "{0} {1} {2} {{ {3}get; {4}set; }}", 196 | AccessibilityAndVirtual(Accessibility.ForNavigationProperty(navProp)), 197 | navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType, 198 | _code.Escape(navProp), 199 | _code.SpaceAfter(Accessibility.ForGetter(navProp)), 200 | _code.SpaceAfter(Accessibility.ForSetter(navProp))); 201 | } 202 | 203 | public string AccessibilityAndVirtual(string accessibility) 204 | { 205 | return accessibility + (accessibility != "private" ? " virtual" : ""); 206 | } 207 | 208 | public string EntityClassOpening(EntityType entity) 209 | { 210 | return string.Format( 211 | CultureInfo.InvariantCulture, 212 | "{0} {1}partial class {2}{3}", 213 | Accessibility.ForType(entity), 214 | _code.SpaceAfter(_code.AbstractOption(entity)), 215 | _code.Escape(entity), 216 | _code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType))); 217 | } 218 | 219 | public string EnumOpening(SimpleType enumType) 220 | { 221 | return string.Format( 222 | CultureInfo.InvariantCulture, 223 | "{0} enum {1} : {2}", 224 | Accessibility.ForType(enumType), 225 | _code.Escape(enumType), 226 | _code.Escape(_typeMapper.UnderlyingClrType(enumType))); 227 | } 228 | 229 | public void WriteFunctionParameters(EdmFunction edmFunction, Action writeParameter) 230 | { 231 | var parameters = FunctionImportParameter.Create(edmFunction.Parameters, _code, _ef); 232 | foreach (var parameter in parameters.Where(p => p.NeedsLocalVariable)) 233 | { 234 | var isNotNull = parameter.IsNullableOfT ? parameter.FunctionParameterName + ".HasValue" : parameter.FunctionParameterName + " != null"; 235 | var notNullInit = "new ObjectParameter(\"" + parameter.EsqlParameterName + "\", " + parameter.FunctionParameterName + ")"; 236 | var nullInit = "new ObjectParameter(\"" + parameter.EsqlParameterName + "\", typeof(" + TypeMapper.FixNamespaces(parameter.RawClrTypeName) + "))"; 237 | writeParameter(parameter.LocalVariableName, isNotNull, notNullInit, nullInit); 238 | } 239 | } 240 | 241 | public string ComposableFunctionMethod(EdmFunction edmFunction, string modelNamespace) 242 | { 243 | var parameters = _typeMapper.GetParameters(edmFunction); 244 | 245 | return string.Format( 246 | CultureInfo.InvariantCulture, 247 | "{0} IQueryable<{1}> {2}({3})", 248 | AccessibilityAndVirtual(Accessibility.ForMethod(edmFunction)), 249 | _typeMapper.GetTypeName(_typeMapper.GetReturnType(edmFunction), modelNamespace), 250 | _code.Escape(edmFunction), 251 | string.Join(", ", parameters.Select(p => TypeMapper.FixNamespaces(p.FunctionParameterType) + " " + p.FunctionParameterName).ToArray())); 252 | } 253 | 254 | public string ComposableCreateQuery(EdmFunction edmFunction, string modelNamespace) 255 | { 256 | var parameters = _typeMapper.GetParameters(edmFunction); 257 | 258 | return string.Format( 259 | CultureInfo.InvariantCulture, 260 | "return ((IObjectContextAdapter)this).ObjectContext.CreateQuery<{0}>(\"[{1}].[{2}]({3})\"{4});", 261 | _typeMapper.GetTypeName(_typeMapper.GetReturnType(edmFunction), modelNamespace), 262 | edmFunction.NamespaceName, 263 | edmFunction.Name, 264 | string.Join(", ", parameters.Select(p => "@" + p.EsqlParameterName).ToArray()), 265 | _code.StringBefore(", ", string.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray()))); 266 | } 267 | 268 | public string FunctionMethod(EdmFunction edmFunction, string modelNamespace, bool includeMergeOption) 269 | { 270 | var parameters = _typeMapper.GetParameters(edmFunction); 271 | var returnType = _typeMapper.GetReturnType(edmFunction); 272 | 273 | var paramList = String.Join(", ", parameters.Select(p => TypeMapper.FixNamespaces(p.FunctionParameterType) + " " + p.FunctionParameterName).ToArray()); 274 | if (includeMergeOption) 275 | { 276 | paramList = _code.StringAfter(paramList, ", ") + "MergeOption mergeOption"; 277 | } 278 | 279 | return string.Format( 280 | CultureInfo.InvariantCulture, 281 | "{0} {1} {2}({3})", 282 | AccessibilityAndVirtual(Accessibility.ForMethod(edmFunction)), 283 | returnType == null ? "int" : "ObjectResult<" + _typeMapper.GetTypeName(returnType, modelNamespace) + ">", 284 | _code.Escape(edmFunction), 285 | paramList); 286 | } 287 | 288 | public string ExecuteFunction(EdmFunction edmFunction, string modelNamespace, bool includeMergeOption) 289 | { 290 | var parameters = _typeMapper.GetParameters(edmFunction); 291 | var returnType = _typeMapper.GetReturnType(edmFunction); 292 | 293 | var callParams = _code.StringBefore(", ", String.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray())); 294 | if (includeMergeOption) 295 | { 296 | callParams = ", mergeOption" + callParams; 297 | } 298 | 299 | return string.Format( 300 | CultureInfo.InvariantCulture, 301 | "return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction{0}(\"{1}\"{2});", 302 | returnType == null ? "" : "<" + _typeMapper.GetTypeName(returnType, modelNamespace) + ">", 303 | edmFunction.Name, 304 | callParams); 305 | } 306 | 307 | public string DbSet(EntitySet entitySet) 308 | { 309 | return string.Format( 310 | CultureInfo.InvariantCulture, 311 | "{0} virtual DbSet<{1}> {2} {{ get; set; }}", 312 | Accessibility.ForReadOnlyProperty(entitySet), 313 | _typeMapper.GetTypeName(entitySet.ElementType), 314 | _code.Escape(entitySet)); 315 | } 316 | 317 | public string DbSetInitializer(EntitySet entitySet) 318 | { 319 | return string.Format( 320 | CultureInfo.InvariantCulture, 321 | "{0} = Set<{1}>();", 322 | _code.Escape(entitySet), 323 | _typeMapper.GetTypeName(entitySet.ElementType)); 324 | } 325 | 326 | public string UsingDirectives(bool inHeader, bool includeCollections = true) 327 | { 328 | return inHeader == string.IsNullOrEmpty(_code.VsNamespaceSuggestion()) 329 | ? string.Format( 330 | CultureInfo.InvariantCulture, 331 | "{0}using System;{1}" + 332 | "{2}", 333 | inHeader ? Environment.NewLine : "", 334 | includeCollections ? (Environment.NewLine + "using System.Collections.Generic;") : "", 335 | inHeader ? "" : Environment.NewLine) 336 | : ""; 337 | } 338 | } 339 | 340 | public class TypeMapper 341 | { 342 | private const string ExternalTypeNameAttributeName = @"http://schemas.microsoft.com/ado/2006/04/codegeneration:ExternalTypeName"; 343 | 344 | private readonly System.Collections.IList _errors; 345 | private readonly CodeGenerationTools _code; 346 | private readonly MetadataTools _ef; 347 | 348 | public static string FixNamespaces(string typeName) 349 | { 350 | return typeName.Replace("System.Data.Spatial.", "System.Data.Entity.Spatial."); 351 | } 352 | 353 | public TypeMapper(CodeGenerationTools code, MetadataTools ef, System.Collections.IList errors) 354 | { 355 | ArgumentNotNull(code, "code"); 356 | ArgumentNotNull(ef, "ef"); 357 | ArgumentNotNull(errors, "errors"); 358 | 359 | _code = code; 360 | _ef = ef; 361 | _errors = errors; 362 | } 363 | 364 | public string GetTypeName(TypeUsage typeUsage) 365 | { 366 | return typeUsage == null ? null : GetTypeName(typeUsage.EdmType, _ef.IsNullable(typeUsage), modelNamespace: null); 367 | } 368 | 369 | public string GetTypeName(EdmType edmType) 370 | { 371 | return GetTypeName(edmType, isNullable: null, modelNamespace: null); 372 | } 373 | 374 | public string GetTypeName(TypeUsage typeUsage, string modelNamespace) 375 | { 376 | return typeUsage == null ? null : GetTypeName(typeUsage.EdmType, _ef.IsNullable(typeUsage), modelNamespace); 377 | } 378 | 379 | public string GetTypeName(EdmType edmType, string modelNamespace) 380 | { 381 | return GetTypeName(edmType, isNullable: null, modelNamespace: modelNamespace); 382 | } 383 | 384 | public string GetTypeName(EdmType edmType, bool? isNullable, string modelNamespace) 385 | { 386 | if (edmType == null) 387 | { 388 | return null; 389 | } 390 | 391 | var collectionType = edmType as CollectionType; 392 | if (collectionType != null) 393 | { 394 | return String.Format(CultureInfo.InvariantCulture, "ICollection<{0}>", GetTypeName(collectionType.TypeUsage, modelNamespace)); 395 | } 396 | 397 | var typeName = _code.Escape(edmType.MetadataProperties 398 | .Where(p => p.Name == ExternalTypeNameAttributeName) 399 | .Select(p => (string)p.Value) 400 | .FirstOrDefault()) 401 | ?? (modelNamespace != null && edmType.NamespaceName != modelNamespace ? 402 | _code.CreateFullName(_code.EscapeNamespace(edmType.NamespaceName), _code.Escape(edmType)) : 403 | _code.Escape(edmType)); 404 | 405 | if (edmType is StructuralType) 406 | { 407 | return typeName; 408 | } 409 | 410 | if (edmType is SimpleType) 411 | { 412 | var clrType = UnderlyingClrType(edmType); 413 | if (!IsEnumType(edmType)) 414 | { 415 | typeName = _code.Escape(clrType); 416 | } 417 | 418 | typeName = FixNamespaces(typeName); 419 | 420 | return clrType.IsValueType && isNullable == true ? 421 | String.Format(CultureInfo.InvariantCulture, "Nullable<{0}>", typeName) : 422 | typeName; 423 | } 424 | 425 | throw new ArgumentException("edmType"); 426 | } 427 | 428 | public Type UnderlyingClrType(EdmType edmType) 429 | { 430 | ArgumentNotNull(edmType, "edmType"); 431 | 432 | var primitiveType = edmType as PrimitiveType; 433 | if (primitiveType != null) 434 | { 435 | return primitiveType.ClrEquivalentType; 436 | } 437 | 438 | if (IsEnumType(edmType)) 439 | { 440 | return GetEnumUnderlyingType(edmType).ClrEquivalentType; 441 | } 442 | 443 | return typeof(object); 444 | } 445 | 446 | public object GetEnumMemberValue(MetadataItem enumMember) 447 | { 448 | ArgumentNotNull(enumMember, "enumMember"); 449 | 450 | var valueProperty = enumMember.GetType().GetProperty("Value"); 451 | return valueProperty == null ? null : valueProperty.GetValue(enumMember, null); 452 | } 453 | 454 | public string GetEnumMemberName(MetadataItem enumMember) 455 | { 456 | ArgumentNotNull(enumMember, "enumMember"); 457 | 458 | var nameProperty = enumMember.GetType().GetProperty("Name"); 459 | return nameProperty == null ? null : (string)nameProperty.GetValue(enumMember, null); 460 | } 461 | 462 | public System.Collections.IEnumerable GetEnumMembers(EdmType enumType) 463 | { 464 | ArgumentNotNull(enumType, "enumType"); 465 | 466 | var membersProperty = enumType.GetType().GetProperty("Members"); 467 | return membersProperty != null 468 | ? (System.Collections.IEnumerable)membersProperty.GetValue(enumType, null) 469 | : Enumerable.Empty(); 470 | } 471 | 472 | public bool EnumIsFlags(EdmType enumType) 473 | { 474 | ArgumentNotNull(enumType, "enumType"); 475 | 476 | var isFlagsProperty = enumType.GetType().GetProperty("IsFlags"); 477 | return isFlagsProperty != null && (bool)isFlagsProperty.GetValue(enumType, null); 478 | } 479 | 480 | public bool IsEnumType(GlobalItem edmType) 481 | { 482 | ArgumentNotNull(edmType, "edmType"); 483 | 484 | return edmType.GetType().Name == "EnumType"; 485 | } 486 | 487 | public PrimitiveType GetEnumUnderlyingType(EdmType enumType) 488 | { 489 | ArgumentNotNull(enumType, "enumType"); 490 | 491 | return (PrimitiveType)enumType.GetType().GetProperty("UnderlyingType").GetValue(enumType, null); 492 | } 493 | 494 | public string CreateLiteral(object value) 495 | { 496 | if (value == null || value.GetType() != typeof(TimeSpan)) 497 | { 498 | return _code.CreateLiteral(value); 499 | } 500 | 501 | return string.Format(CultureInfo.InvariantCulture, "new TimeSpan({0})", ((TimeSpan)value).Ticks); 502 | } 503 | 504 | public bool VerifyCaseInsensitiveTypeUniqueness(IEnumerable types, string sourceFile) 505 | { 506 | ArgumentNotNull(types, "types"); 507 | ArgumentNotNull(sourceFile, "sourceFile"); 508 | 509 | var hash = new HashSet(StringComparer.InvariantCultureIgnoreCase); 510 | if (types.Any(item => !hash.Add(item))) 511 | { 512 | _errors.Add( 513 | new CompilerError(sourceFile, -1, -1, "6023", 514 | String.Format(CultureInfo.CurrentCulture, CodeGenerationTools.GetResourceString("Template_CaseInsensitiveTypeConflict")))); 515 | return false; 516 | } 517 | return true; 518 | } 519 | 520 | public IEnumerable GetEnumItemsToGenerate(IEnumerable itemCollection) 521 | { 522 | return GetItemsToGenerate(itemCollection) 523 | .Where(e => IsEnumType(e)); 524 | } 525 | 526 | public IEnumerable GetItemsToGenerate(IEnumerable itemCollection) where T: EdmType 527 | { 528 | return itemCollection 529 | .OfType() 530 | .Where(i => !i.MetadataProperties.Any(p => p.Name == ExternalTypeNameAttributeName)) 531 | .OrderBy(i => i.Name); 532 | } 533 | 534 | public IEnumerable GetAllGlobalItems(IEnumerable itemCollection) 535 | { 536 | return itemCollection 537 | .Where(i => i is EntityType || i is ComplexType || i is EntityContainer || IsEnumType(i)) 538 | .Select(g => GetGlobalItemName(g)); 539 | } 540 | 541 | public string GetGlobalItemName(GlobalItem item) 542 | { 543 | if (item is EdmType) 544 | { 545 | return ((EdmType)item).Name; 546 | } 547 | else 548 | { 549 | return ((EntityContainer)item).Name; 550 | } 551 | } 552 | 553 | public IEnumerable GetSimpleProperties(EntityType type) 554 | { 555 | return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type); 556 | } 557 | 558 | public IEnumerable GetSimpleProperties(ComplexType type) 559 | { 560 | return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type); 561 | } 562 | 563 | public IEnumerable GetComplexProperties(EntityType type) 564 | { 565 | return type.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == type); 566 | } 567 | 568 | public IEnumerable GetComplexProperties(ComplexType type) 569 | { 570 | return type.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == type); 571 | } 572 | 573 | public IEnumerable GetPropertiesWithDefaultValues(EntityType type) 574 | { 575 | return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type && p.DefaultValue != null); 576 | } 577 | 578 | public IEnumerable GetPropertiesWithDefaultValues(ComplexType type) 579 | { 580 | return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type && p.DefaultValue != null); 581 | } 582 | 583 | public IEnumerable GetNavigationProperties(EntityType type) 584 | { 585 | return type.NavigationProperties.Where(np => np.DeclaringType == type); 586 | } 587 | 588 | public IEnumerable GetCollectionNavigationProperties(EntityType type) 589 | { 590 | return type.NavigationProperties.Where(np => np.DeclaringType == type && np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many); 591 | } 592 | 593 | public FunctionParameter GetReturnParameter(EdmFunction edmFunction) 594 | { 595 | ArgumentNotNull(edmFunction, "edmFunction"); 596 | 597 | var returnParamsProperty = edmFunction.GetType().GetProperty("ReturnParameters"); 598 | return returnParamsProperty == null 599 | ? edmFunction.ReturnParameter 600 | : ((IEnumerable)returnParamsProperty.GetValue(edmFunction, null)).FirstOrDefault(); 601 | } 602 | 603 | public bool IsComposable(EdmFunction edmFunction) 604 | { 605 | ArgumentNotNull(edmFunction, "edmFunction"); 606 | 607 | var isComposableProperty = edmFunction.GetType().GetProperty("IsComposableAttribute"); 608 | return isComposableProperty != null && (bool)isComposableProperty.GetValue(edmFunction, null); 609 | } 610 | 611 | public IEnumerable GetParameters(EdmFunction edmFunction) 612 | { 613 | return FunctionImportParameter.Create(edmFunction.Parameters, _code, _ef); 614 | } 615 | 616 | public TypeUsage GetReturnType(EdmFunction edmFunction) 617 | { 618 | var returnParam = GetReturnParameter(edmFunction); 619 | return returnParam == null ? null : _ef.GetElementType(returnParam.TypeUsage); 620 | } 621 | 622 | public bool GenerateMergeOptionFunction(EdmFunction edmFunction, bool includeMergeOption) 623 | { 624 | var returnType = GetReturnType(edmFunction); 625 | return !includeMergeOption && returnType != null && returnType.EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType; 626 | } 627 | } 628 | 629 | public static void ArgumentNotNull(T arg, string name) where T : class 630 | { 631 | if (arg == null) 632 | { 633 | throw new ArgumentNullException(name); 634 | } 635 | } 636 | #> -------------------------------------------------------------------------------- /Test/Models/TestContext.Designer.cs: -------------------------------------------------------------------------------- 1 | // T4 code generation is enabled for model 'C:\Development\Projects\Shared\Sources\Dapper.EntityFramework.Extensions\Test\Models\TestContext.edmx'. 2 | // To enable legacy code generation, change the value of the 'Code Generation Strategy' designer 3 | // property to 'Legacy ObjectContext'. This property is available in the Properties Window when the model 4 | // is open in the designer. 5 | 6 | // If no context and entity classes have been generated, it may be because you created an empty model but 7 | // have not yet chosen which version of Entity Framework to use. To generate a context class and entity 8 | // classes for your model, open the model in the designer, right-click on the designer surface, and 9 | // select 'Update Model from Database...', 'Generate Database from Model...', or 'Add Code Generation 10 | // Item...'. -------------------------------------------------------------------------------- /Test/Models/TestContext.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated from a template. 4 | // 5 | // Manual changes to this file may cause unexpected behavior in your application. 6 | // Manual changes to this file will be overwritten if the code is regenerated. 7 | // 8 | //------------------------------------------------------------------------------ 9 | 10 | -------------------------------------------------------------------------------- /Test/Models/TestContext.edmx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | -------------------------------------------------------------------------------- /Test/Models/TestContext.edmx.diagram: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Test/Models/TestContext.tt: -------------------------------------------------------------------------------- 1 | <#@ template language="C#" debug="false" hostspecific="true"#> 2 | <#@ include file="EF6.Utility.CS.ttinclude"#><#@ 3 | output extension=".cs"#><# 4 | 5 | const string inputFile = @"TestContext.edmx"; 6 | var textTransform = DynamicTextTransformation.Create(this); 7 | var code = new CodeGenerationTools(this); 8 | var ef = new MetadataTools(this); 9 | var typeMapper = new TypeMapper(code, ef, textTransform.Errors); 10 | var fileManager = EntityFrameworkTemplateFileManager.Create(this); 11 | var itemCollection = new EdmMetadataLoader(textTransform.Host, textTransform.Errors).CreateEdmItemCollection(inputFile); 12 | var codeStringGenerator = new CodeStringGenerator(code, typeMapper, ef); 13 | 14 | if (!typeMapper.VerifyCaseInsensitiveTypeUniqueness(typeMapper.GetAllGlobalItems(itemCollection), inputFile)) 15 | { 16 | return string.Empty; 17 | } 18 | 19 | WriteHeader(codeStringGenerator, fileManager); 20 | 21 | foreach (var entity in typeMapper.GetItemsToGenerate(itemCollection)) 22 | { 23 | fileManager.StartNewFile(entity.Name + ".cs"); 24 | BeginNamespace(code); 25 | #> 26 | <#=codeStringGenerator.UsingDirectives(inHeader: false)#> 27 | <#=codeStringGenerator.EntityClassOpening(entity)#> 28 | { 29 | <# 30 | var propertiesWithDefaultValues = typeMapper.GetPropertiesWithDefaultValues(entity); 31 | var collectionNavigationProperties = typeMapper.GetCollectionNavigationProperties(entity); 32 | var complexProperties = typeMapper.GetComplexProperties(entity); 33 | 34 | if (propertiesWithDefaultValues.Any() || collectionNavigationProperties.Any() || complexProperties.Any()) 35 | { 36 | #> 37 | public <#=code.Escape(entity)#>() 38 | { 39 | <# 40 | foreach (var edmProperty in propertiesWithDefaultValues) 41 | { 42 | #> 43 | this.<#=code.Escape(edmProperty)#> = <#=typeMapper.CreateLiteral(edmProperty.DefaultValue)#>; 44 | <# 45 | } 46 | 47 | foreach (var navigationProperty in collectionNavigationProperties) 48 | { 49 | #> 50 | this.<#=code.Escape(navigationProperty)#> = new HashSet<<#=typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType())#>>(); 51 | <# 52 | } 53 | 54 | foreach (var complexProperty in complexProperties) 55 | { 56 | #> 57 | this.<#=code.Escape(complexProperty)#> = new <#=typeMapper.GetTypeName(complexProperty.TypeUsage)#>(); 58 | <# 59 | } 60 | #> 61 | } 62 | 63 | <# 64 | } 65 | 66 | var simpleProperties = typeMapper.GetSimpleProperties(entity); 67 | if (simpleProperties.Any()) 68 | { 69 | foreach (var edmProperty in simpleProperties) 70 | { 71 | #> 72 | <#=codeStringGenerator.Property(edmProperty)#> 73 | <# 74 | } 75 | } 76 | 77 | if (complexProperties.Any()) 78 | { 79 | #> 80 | 81 | <# 82 | foreach(var complexProperty in complexProperties) 83 | { 84 | #> 85 | <#=codeStringGenerator.Property(complexProperty)#> 86 | <# 87 | } 88 | } 89 | 90 | var navigationProperties = typeMapper.GetNavigationProperties(entity); 91 | if (navigationProperties.Any()) 92 | { 93 | #> 94 | 95 | <# 96 | foreach (var navigationProperty in navigationProperties) 97 | { 98 | #> 99 | <#=codeStringGenerator.NavigationProperty(navigationProperty)#> 100 | <# 101 | } 102 | } 103 | #> 104 | } 105 | <# 106 | EndNamespace(code); 107 | } 108 | 109 | foreach (var complex in typeMapper.GetItemsToGenerate(itemCollection)) 110 | { 111 | fileManager.StartNewFile(complex.Name + ".cs"); 112 | BeginNamespace(code); 113 | #> 114 | <#=codeStringGenerator.UsingDirectives(inHeader: false, includeCollections: false)#> 115 | <#=Accessibility.ForType(complex)#> partial class <#=code.Escape(complex)#> 116 | { 117 | <# 118 | var complexProperties = typeMapper.GetComplexProperties(complex); 119 | var propertiesWithDefaultValues = typeMapper.GetPropertiesWithDefaultValues(complex); 120 | 121 | if (propertiesWithDefaultValues.Any() || complexProperties.Any()) 122 | { 123 | #> 124 | public <#=code.Escape(complex)#>() 125 | { 126 | <# 127 | foreach (var edmProperty in propertiesWithDefaultValues) 128 | { 129 | #> 130 | this.<#=code.Escape(edmProperty)#> = <#=typeMapper.CreateLiteral(edmProperty.DefaultValue)#>; 131 | <# 132 | } 133 | 134 | foreach (var complexProperty in complexProperties) 135 | { 136 | #> 137 | this.<#=code.Escape(complexProperty)#> = new <#=typeMapper.GetTypeName(complexProperty.TypeUsage)#>(); 138 | <# 139 | } 140 | #> 141 | } 142 | 143 | <# 144 | } 145 | 146 | var simpleProperties = typeMapper.GetSimpleProperties(complex); 147 | if (simpleProperties.Any()) 148 | { 149 | foreach(var edmProperty in simpleProperties) 150 | { 151 | #> 152 | <#=codeStringGenerator.Property(edmProperty)#> 153 | <# 154 | } 155 | } 156 | 157 | if (complexProperties.Any()) 158 | { 159 | #> 160 | 161 | <# 162 | foreach(var edmProperty in complexProperties) 163 | { 164 | #> 165 | <#=codeStringGenerator.Property(edmProperty)#> 166 | <# 167 | } 168 | } 169 | #> 170 | } 171 | <# 172 | EndNamespace(code); 173 | } 174 | 175 | foreach (var enumType in typeMapper.GetEnumItemsToGenerate(itemCollection)) 176 | { 177 | fileManager.StartNewFile(enumType.Name + ".cs"); 178 | BeginNamespace(code); 179 | #> 180 | <#=codeStringGenerator.UsingDirectives(inHeader: false, includeCollections: false)#> 181 | <# 182 | if (typeMapper.EnumIsFlags(enumType)) 183 | { 184 | #> 185 | [Flags] 186 | <# 187 | } 188 | #> 189 | <#=codeStringGenerator.EnumOpening(enumType)#> 190 | { 191 | <# 192 | var foundOne = false; 193 | 194 | foreach (MetadataItem member in typeMapper.GetEnumMembers(enumType)) 195 | { 196 | foundOne = true; 197 | #> 198 | <#=code.Escape(typeMapper.GetEnumMemberName(member))#> = <#=typeMapper.GetEnumMemberValue(member)#>, 199 | <# 200 | } 201 | 202 | if (foundOne) 203 | { 204 | this.GenerationEnvironment.Remove(this.GenerationEnvironment.Length - 3, 1); 205 | } 206 | #> 207 | } 208 | <# 209 | EndNamespace(code); 210 | } 211 | 212 | fileManager.Process(); 213 | 214 | #> 215 | <#+ 216 | 217 | public void WriteHeader(CodeStringGenerator codeStringGenerator, EntityFrameworkTemplateFileManager fileManager) 218 | { 219 | fileManager.StartHeader(); 220 | #> 221 | //------------------------------------------------------------------------------ 222 | // 223 | // <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine1")#> 224 | // 225 | // <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine2")#> 226 | // <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine3")#> 227 | // 228 | //------------------------------------------------------------------------------ 229 | <#=codeStringGenerator.UsingDirectives(inHeader: true)#> 230 | <#+ 231 | fileManager.EndBlock(); 232 | } 233 | 234 | public void BeginNamespace(CodeGenerationTools code) 235 | { 236 | var codeNamespace = code.VsNamespaceSuggestion(); 237 | if (!String.IsNullOrEmpty(codeNamespace)) 238 | { 239 | #> 240 | namespace <#=code.EscapeNamespace(codeNamespace)#> 241 | { 242 | <#+ 243 | PushIndent(" "); 244 | } 245 | } 246 | 247 | public void EndNamespace(CodeGenerationTools code) 248 | { 249 | if (!String.IsNullOrEmpty(code.VsNamespaceSuggestion())) 250 | { 251 | PopIndent(); 252 | #> 253 | } 254 | <#+ 255 | } 256 | } 257 | 258 | public const string TemplateId = "CSharp_DbContext_Types_EF6"; 259 | 260 | public class CodeStringGenerator 261 | { 262 | private readonly CodeGenerationTools _code; 263 | private readonly TypeMapper _typeMapper; 264 | private readonly MetadataTools _ef; 265 | 266 | public CodeStringGenerator(CodeGenerationTools code, TypeMapper typeMapper, MetadataTools ef) 267 | { 268 | ArgumentNotNull(code, "code"); 269 | ArgumentNotNull(typeMapper, "typeMapper"); 270 | ArgumentNotNull(ef, "ef"); 271 | 272 | _code = code; 273 | _typeMapper = typeMapper; 274 | _ef = ef; 275 | } 276 | 277 | public string Property(EdmProperty edmProperty) 278 | { 279 | return string.Format( 280 | CultureInfo.InvariantCulture, 281 | "{0} {1} {2} {{ {3}get; {4}set; }}", 282 | Accessibility.ForProperty(edmProperty), 283 | _typeMapper.GetTypeName(edmProperty.TypeUsage), 284 | _code.Escape(edmProperty), 285 | _code.SpaceAfter(Accessibility.ForGetter(edmProperty)), 286 | _code.SpaceAfter(Accessibility.ForSetter(edmProperty))); 287 | } 288 | 289 | public string NavigationProperty(NavigationProperty navProp) 290 | { 291 | var endType = _typeMapper.GetTypeName(navProp.ToEndMember.GetEntityType()); 292 | return string.Format( 293 | CultureInfo.InvariantCulture, 294 | "{0} {1} {2} {{ {3}get; {4}set; }}", 295 | AccessibilityAndVirtual(Accessibility.ForNavigationProperty(navProp)), 296 | navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType, 297 | _code.Escape(navProp), 298 | _code.SpaceAfter(Accessibility.ForGetter(navProp)), 299 | _code.SpaceAfter(Accessibility.ForSetter(navProp))); 300 | } 301 | 302 | public string AccessibilityAndVirtual(string accessibility) 303 | { 304 | return accessibility + (accessibility != "private" ? " virtual" : ""); 305 | } 306 | 307 | public string EntityClassOpening(EntityType entity) 308 | { 309 | return string.Format( 310 | CultureInfo.InvariantCulture, 311 | "{0} {1}partial class {2}{3}", 312 | Accessibility.ForType(entity), 313 | _code.SpaceAfter(_code.AbstractOption(entity)), 314 | _code.Escape(entity), 315 | _code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType))); 316 | } 317 | 318 | public string EnumOpening(SimpleType enumType) 319 | { 320 | return string.Format( 321 | CultureInfo.InvariantCulture, 322 | "{0} enum {1} : {2}", 323 | Accessibility.ForType(enumType), 324 | _code.Escape(enumType), 325 | _code.Escape(_typeMapper.UnderlyingClrType(enumType))); 326 | } 327 | 328 | public void WriteFunctionParameters(EdmFunction edmFunction, Action writeParameter) 329 | { 330 | var parameters = FunctionImportParameter.Create(edmFunction.Parameters, _code, _ef); 331 | foreach (var parameter in parameters.Where(p => p.NeedsLocalVariable)) 332 | { 333 | var isNotNull = parameter.IsNullableOfT ? parameter.FunctionParameterName + ".HasValue" : parameter.FunctionParameterName + " != null"; 334 | var notNullInit = "new ObjectParameter(\"" + parameter.EsqlParameterName + "\", " + parameter.FunctionParameterName + ")"; 335 | var nullInit = "new ObjectParameter(\"" + parameter.EsqlParameterName + "\", typeof(" + TypeMapper.FixNamespaces(parameter.RawClrTypeName) + "))"; 336 | writeParameter(parameter.LocalVariableName, isNotNull, notNullInit, nullInit); 337 | } 338 | } 339 | 340 | public string ComposableFunctionMethod(EdmFunction edmFunction, string modelNamespace) 341 | { 342 | var parameters = _typeMapper.GetParameters(edmFunction); 343 | 344 | return string.Format( 345 | CultureInfo.InvariantCulture, 346 | "{0} IQueryable<{1}> {2}({3})", 347 | AccessibilityAndVirtual(Accessibility.ForMethod(edmFunction)), 348 | _typeMapper.GetTypeName(_typeMapper.GetReturnType(edmFunction), modelNamespace), 349 | _code.Escape(edmFunction), 350 | string.Join(", ", parameters.Select(p => TypeMapper.FixNamespaces(p.FunctionParameterType) + " " + p.FunctionParameterName).ToArray())); 351 | } 352 | 353 | public string ComposableCreateQuery(EdmFunction edmFunction, string modelNamespace) 354 | { 355 | var parameters = _typeMapper.GetParameters(edmFunction); 356 | 357 | return string.Format( 358 | CultureInfo.InvariantCulture, 359 | "return ((IObjectContextAdapter)this).ObjectContext.CreateQuery<{0}>(\"[{1}].[{2}]({3})\"{4});", 360 | _typeMapper.GetTypeName(_typeMapper.GetReturnType(edmFunction), modelNamespace), 361 | edmFunction.NamespaceName, 362 | edmFunction.Name, 363 | string.Join(", ", parameters.Select(p => "@" + p.EsqlParameterName).ToArray()), 364 | _code.StringBefore(", ", string.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray()))); 365 | } 366 | 367 | public string FunctionMethod(EdmFunction edmFunction, string modelNamespace, bool includeMergeOption) 368 | { 369 | var parameters = _typeMapper.GetParameters(edmFunction); 370 | var returnType = _typeMapper.GetReturnType(edmFunction); 371 | 372 | var paramList = String.Join(", ", parameters.Select(p => TypeMapper.FixNamespaces(p.FunctionParameterType) + " " + p.FunctionParameterName).ToArray()); 373 | if (includeMergeOption) 374 | { 375 | paramList = _code.StringAfter(paramList, ", ") + "MergeOption mergeOption"; 376 | } 377 | 378 | return string.Format( 379 | CultureInfo.InvariantCulture, 380 | "{0} {1} {2}({3})", 381 | AccessibilityAndVirtual(Accessibility.ForMethod(edmFunction)), 382 | returnType == null ? "int" : "ObjectResult<" + _typeMapper.GetTypeName(returnType, modelNamespace) + ">", 383 | _code.Escape(edmFunction), 384 | paramList); 385 | } 386 | 387 | public string ExecuteFunction(EdmFunction edmFunction, string modelNamespace, bool includeMergeOption) 388 | { 389 | var parameters = _typeMapper.GetParameters(edmFunction); 390 | var returnType = _typeMapper.GetReturnType(edmFunction); 391 | 392 | var callParams = _code.StringBefore(", ", String.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray())); 393 | if (includeMergeOption) 394 | { 395 | callParams = ", mergeOption" + callParams; 396 | } 397 | 398 | return string.Format( 399 | CultureInfo.InvariantCulture, 400 | "return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction{0}(\"{1}\"{2});", 401 | returnType == null ? "" : "<" + _typeMapper.GetTypeName(returnType, modelNamespace) + ">", 402 | edmFunction.Name, 403 | callParams); 404 | } 405 | 406 | public string DbSet(EntitySet entitySet) 407 | { 408 | return string.Format( 409 | CultureInfo.InvariantCulture, 410 | "{0} virtual DbSet<{1}> {2} {{ get; set; }}", 411 | Accessibility.ForReadOnlyProperty(entitySet), 412 | _typeMapper.GetTypeName(entitySet.ElementType), 413 | _code.Escape(entitySet)); 414 | } 415 | 416 | public string UsingDirectives(bool inHeader, bool includeCollections = true) 417 | { 418 | return inHeader == string.IsNullOrEmpty(_code.VsNamespaceSuggestion()) 419 | ? string.Format( 420 | CultureInfo.InvariantCulture, 421 | "{0}using System;{1}" + 422 | "{2}", 423 | inHeader ? Environment.NewLine : "", 424 | includeCollections ? (Environment.NewLine + "using System.Collections.Generic;") : "", 425 | inHeader ? "" : Environment.NewLine) 426 | : ""; 427 | } 428 | } 429 | 430 | public class TypeMapper 431 | { 432 | private const string ExternalTypeNameAttributeName = @"http://schemas.microsoft.com/ado/2006/04/codegeneration:ExternalTypeName"; 433 | 434 | private readonly System.Collections.IList _errors; 435 | private readonly CodeGenerationTools _code; 436 | private readonly MetadataTools _ef; 437 | 438 | public TypeMapper(CodeGenerationTools code, MetadataTools ef, System.Collections.IList errors) 439 | { 440 | ArgumentNotNull(code, "code"); 441 | ArgumentNotNull(ef, "ef"); 442 | ArgumentNotNull(errors, "errors"); 443 | 444 | _code = code; 445 | _ef = ef; 446 | _errors = errors; 447 | } 448 | 449 | public static string FixNamespaces(string typeName) 450 | { 451 | return typeName.Replace("System.Data.Spatial.", "System.Data.Entity.Spatial."); 452 | } 453 | 454 | public string GetTypeName(TypeUsage typeUsage) 455 | { 456 | return typeUsage == null ? null : GetTypeName(typeUsage.EdmType, _ef.IsNullable(typeUsage), modelNamespace: null); 457 | } 458 | 459 | public string GetTypeName(EdmType edmType) 460 | { 461 | return GetTypeName(edmType, isNullable: null, modelNamespace: null); 462 | } 463 | 464 | public string GetTypeName(TypeUsage typeUsage, string modelNamespace) 465 | { 466 | return typeUsage == null ? null : GetTypeName(typeUsage.EdmType, _ef.IsNullable(typeUsage), modelNamespace); 467 | } 468 | 469 | public string GetTypeName(EdmType edmType, string modelNamespace) 470 | { 471 | return GetTypeName(edmType, isNullable: null, modelNamespace: modelNamespace); 472 | } 473 | 474 | public string GetTypeName(EdmType edmType, bool? isNullable, string modelNamespace) 475 | { 476 | if (edmType == null) 477 | { 478 | return null; 479 | } 480 | 481 | var collectionType = edmType as CollectionType; 482 | if (collectionType != null) 483 | { 484 | return String.Format(CultureInfo.InvariantCulture, "ICollection<{0}>", GetTypeName(collectionType.TypeUsage, modelNamespace)); 485 | } 486 | 487 | var typeName = _code.Escape(edmType.MetadataProperties 488 | .Where(p => p.Name == ExternalTypeNameAttributeName) 489 | .Select(p => (string)p.Value) 490 | .FirstOrDefault()) 491 | ?? (modelNamespace != null && edmType.NamespaceName != modelNamespace ? 492 | _code.CreateFullName(_code.EscapeNamespace(edmType.NamespaceName), _code.Escape(edmType)) : 493 | _code.Escape(edmType)); 494 | 495 | if (edmType is StructuralType) 496 | { 497 | return typeName; 498 | } 499 | 500 | if (edmType is SimpleType) 501 | { 502 | var clrType = UnderlyingClrType(edmType); 503 | if (!IsEnumType(edmType)) 504 | { 505 | typeName = _code.Escape(clrType); 506 | } 507 | 508 | typeName = FixNamespaces(typeName); 509 | 510 | return clrType.IsValueType && isNullable == true ? 511 | String.Format(CultureInfo.InvariantCulture, "Nullable<{0}>", typeName) : 512 | typeName; 513 | } 514 | 515 | throw new ArgumentException("edmType"); 516 | } 517 | 518 | public Type UnderlyingClrType(EdmType edmType) 519 | { 520 | ArgumentNotNull(edmType, "edmType"); 521 | 522 | var primitiveType = edmType as PrimitiveType; 523 | if (primitiveType != null) 524 | { 525 | return primitiveType.ClrEquivalentType; 526 | } 527 | 528 | if (IsEnumType(edmType)) 529 | { 530 | return GetEnumUnderlyingType(edmType).ClrEquivalentType; 531 | } 532 | 533 | return typeof(object); 534 | } 535 | 536 | public object GetEnumMemberValue(MetadataItem enumMember) 537 | { 538 | ArgumentNotNull(enumMember, "enumMember"); 539 | 540 | var valueProperty = enumMember.GetType().GetProperty("Value"); 541 | return valueProperty == null ? null : valueProperty.GetValue(enumMember, null); 542 | } 543 | 544 | public string GetEnumMemberName(MetadataItem enumMember) 545 | { 546 | ArgumentNotNull(enumMember, "enumMember"); 547 | 548 | var nameProperty = enumMember.GetType().GetProperty("Name"); 549 | return nameProperty == null ? null : (string)nameProperty.GetValue(enumMember, null); 550 | } 551 | 552 | public System.Collections.IEnumerable GetEnumMembers(EdmType enumType) 553 | { 554 | ArgumentNotNull(enumType, "enumType"); 555 | 556 | var membersProperty = enumType.GetType().GetProperty("Members"); 557 | return membersProperty != null 558 | ? (System.Collections.IEnumerable)membersProperty.GetValue(enumType, null) 559 | : Enumerable.Empty(); 560 | } 561 | 562 | public bool EnumIsFlags(EdmType enumType) 563 | { 564 | ArgumentNotNull(enumType, "enumType"); 565 | 566 | var isFlagsProperty = enumType.GetType().GetProperty("IsFlags"); 567 | return isFlagsProperty != null && (bool)isFlagsProperty.GetValue(enumType, null); 568 | } 569 | 570 | public bool IsEnumType(GlobalItem edmType) 571 | { 572 | ArgumentNotNull(edmType, "edmType"); 573 | 574 | return edmType.GetType().Name == "EnumType"; 575 | } 576 | 577 | public PrimitiveType GetEnumUnderlyingType(EdmType enumType) 578 | { 579 | ArgumentNotNull(enumType, "enumType"); 580 | 581 | return (PrimitiveType)enumType.GetType().GetProperty("UnderlyingType").GetValue(enumType, null); 582 | } 583 | 584 | public string CreateLiteral(object value) 585 | { 586 | if (value == null || value.GetType() != typeof(TimeSpan)) 587 | { 588 | return _code.CreateLiteral(value); 589 | } 590 | 591 | return string.Format(CultureInfo.InvariantCulture, "new TimeSpan({0})", ((TimeSpan)value).Ticks); 592 | } 593 | 594 | public bool VerifyCaseInsensitiveTypeUniqueness(IEnumerable types, string sourceFile) 595 | { 596 | ArgumentNotNull(types, "types"); 597 | ArgumentNotNull(sourceFile, "sourceFile"); 598 | 599 | var hash = new HashSet(StringComparer.InvariantCultureIgnoreCase); 600 | if (types.Any(item => !hash.Add(item))) 601 | { 602 | _errors.Add( 603 | new CompilerError(sourceFile, -1, -1, "6023", 604 | String.Format(CultureInfo.CurrentCulture, CodeGenerationTools.GetResourceString("Template_CaseInsensitiveTypeConflict")))); 605 | return false; 606 | } 607 | return true; 608 | } 609 | 610 | public IEnumerable GetEnumItemsToGenerate(IEnumerable itemCollection) 611 | { 612 | return GetItemsToGenerate(itemCollection) 613 | .Where(e => IsEnumType(e)); 614 | } 615 | 616 | public IEnumerable GetItemsToGenerate(IEnumerable itemCollection) where T: EdmType 617 | { 618 | return itemCollection 619 | .OfType() 620 | .Where(i => !i.MetadataProperties.Any(p => p.Name == ExternalTypeNameAttributeName)) 621 | .OrderBy(i => i.Name); 622 | } 623 | 624 | public IEnumerable GetAllGlobalItems(IEnumerable itemCollection) 625 | { 626 | return itemCollection 627 | .Where(i => i is EntityType || i is ComplexType || i is EntityContainer || IsEnumType(i)) 628 | .Select(g => GetGlobalItemName(g)); 629 | } 630 | 631 | public string GetGlobalItemName(GlobalItem item) 632 | { 633 | if (item is EdmType) 634 | { 635 | return ((EdmType)item).Name; 636 | } 637 | else 638 | { 639 | return ((EntityContainer)item).Name; 640 | } 641 | } 642 | 643 | public IEnumerable GetSimpleProperties(EntityType type) 644 | { 645 | return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type); 646 | } 647 | 648 | public IEnumerable GetSimpleProperties(ComplexType type) 649 | { 650 | return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type); 651 | } 652 | 653 | public IEnumerable GetComplexProperties(EntityType type) 654 | { 655 | return type.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == type); 656 | } 657 | 658 | public IEnumerable GetComplexProperties(ComplexType type) 659 | { 660 | return type.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == type); 661 | } 662 | 663 | public IEnumerable GetPropertiesWithDefaultValues(EntityType type) 664 | { 665 | return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type && p.DefaultValue != null); 666 | } 667 | 668 | public IEnumerable GetPropertiesWithDefaultValues(ComplexType type) 669 | { 670 | return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type && p.DefaultValue != null); 671 | } 672 | 673 | public IEnumerable GetNavigationProperties(EntityType type) 674 | { 675 | return type.NavigationProperties.Where(np => np.DeclaringType == type); 676 | } 677 | 678 | public IEnumerable GetCollectionNavigationProperties(EntityType type) 679 | { 680 | return type.NavigationProperties.Where(np => np.DeclaringType == type && np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many); 681 | } 682 | 683 | public FunctionParameter GetReturnParameter(EdmFunction edmFunction) 684 | { 685 | ArgumentNotNull(edmFunction, "edmFunction"); 686 | 687 | var returnParamsProperty = edmFunction.GetType().GetProperty("ReturnParameters"); 688 | return returnParamsProperty == null 689 | ? edmFunction.ReturnParameter 690 | : ((IEnumerable)returnParamsProperty.GetValue(edmFunction, null)).FirstOrDefault(); 691 | } 692 | 693 | public bool IsComposable(EdmFunction edmFunction) 694 | { 695 | ArgumentNotNull(edmFunction, "edmFunction"); 696 | 697 | var isComposableProperty = edmFunction.GetType().GetProperty("IsComposableAttribute"); 698 | return isComposableProperty != null && (bool)isComposableProperty.GetValue(edmFunction, null); 699 | } 700 | 701 | public IEnumerable GetParameters(EdmFunction edmFunction) 702 | { 703 | return FunctionImportParameter.Create(edmFunction.Parameters, _code, _ef); 704 | } 705 | 706 | public TypeUsage GetReturnType(EdmFunction edmFunction) 707 | { 708 | var returnParam = GetReturnParameter(edmFunction); 709 | return returnParam == null ? null : _ef.GetElementType(returnParam.TypeUsage); 710 | } 711 | 712 | public bool GenerateMergeOptionFunction(EdmFunction edmFunction, bool includeMergeOption) 713 | { 714 | var returnType = GetReturnType(edmFunction); 715 | return !includeMergeOption && returnType != null && returnType.EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType; 716 | } 717 | } 718 | 719 | public static void ArgumentNotNull(T arg, string name) where T : class 720 | { 721 | if (arg == null) 722 | { 723 | throw new ArgumentNullException(name); 724 | } 725 | } 726 | #> -------------------------------------------------------------------------------- /Test/Models/User.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated from a template. 4 | // 5 | // Manual changes to this file may cause unexpected behavior in your application. 6 | // Manual changes to this file will be overwritten if the code is regenerated. 7 | // 8 | //------------------------------------------------------------------------------ 9 | 10 | namespace Test.Models 11 | { 12 | using System; 13 | using System.Collections.Generic; 14 | 15 | public partial class User 16 | { 17 | public User() 18 | { 19 | this.Blogs = new HashSet(); 20 | } 21 | 22 | public int Id { get; set; } 23 | public string Name { get; set; } 24 | public System.DateTime DateCreate { get; set; } 25 | public Gender Gender { get; set; } 26 | 27 | public virtual ICollection Blogs { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Test/Models/sysdiagram.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated from a template. 4 | // 5 | // Manual changes to this file may cause unexpected behavior in your application. 6 | // Manual changes to this file will be overwritten if the code is regenerated. 7 | // 8 | //------------------------------------------------------------------------------ 9 | 10 | namespace Test.Models 11 | { 12 | using System; 13 | using System.Collections.Generic; 14 | 15 | public partial class sysdiagram 16 | { 17 | public string name { get; set; } 18 | public int principal_id { get; set; } 19 | public int diagram_id { get; set; } 20 | public Nullable version { get; set; } 21 | public byte[] definition { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Test/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Test.Models; 7 | using Dapper; 8 | using System.Linq.Expressions; 9 | using System.Diagnostics; 10 | using System.Data.Entity.Infrastructure; 11 | using System.Data.Entity.Core.Objects; 12 | 13 | namespace Test 14 | { 15 | class Program 16 | { 17 | static Stopwatch watch = new Stopwatch(); 18 | static void Main(string[] args) 19 | { 20 | watch.Restart(); 21 | using (TestEntities context = new TestEntities()) 22 | { 23 | //context.Optimization(); 24 | context.Initialize(); 25 | } 26 | Console.WriteLine("{0}ms - Initialize Context", watch.ElapsedMilliseconds); 27 | 28 | TestsDapper(); 29 | Tests(); 30 | TestsEF(); 31 | 32 | Console.ReadLine(); 33 | } 34 | 35 | public static void Tests() 36 | { 37 | Console.WriteLine(); 38 | Console.WriteLine("##### EXTENSIONS"); 39 | Console.WriteLine(); 40 | Insert(); 41 | Update(); 42 | Delete(); 43 | Select(); 44 | ToDapper(); 45 | } 46 | 47 | public static void TestsDapper() 48 | { 49 | Console.WriteLine(); 50 | Console.WriteLine("##### DAPPER"); 51 | Console.WriteLine(); 52 | InsertDapper(); 53 | UpdateDapper(); 54 | DeleteDapper(); 55 | SelectDapper(); 56 | } 57 | 58 | public static void TestsEF() 59 | { 60 | Console.WriteLine(); 61 | Console.WriteLine("##### ENTITYFRAMEWORK"); 62 | Console.WriteLine(); 63 | InsertEF(); 64 | UpdateEF(); 65 | //Delete(); 66 | //Select(); 67 | } 68 | 69 | #region Tests Extensions 70 | public static void Insert() 71 | { 72 | using (TestEntities context = new TestEntities()) 73 | { 74 | var obj = new 75 | { 76 | Name = "User Insert", 77 | DateCreate = DateTime.Now, 78 | Gender = Gender.Female 79 | }; 80 | watch.Restart(); 81 | context.Users.Insert(obj); 82 | Console.WriteLine("Insert With Anonymous - {0}ms", watch.ElapsedMilliseconds); 83 | 84 | Console.WriteLine(); 85 | watch.Restart(); 86 | var obj2 = new User() 87 | { 88 | Name = "User Insert", 89 | DateCreate = DateTime.Now, 90 | Gender = Gender.Male 91 | }; 92 | context.Users.Insert(obj2); 93 | Console.WriteLine("Insert With Class - {0}ms", watch.ElapsedMilliseconds); 94 | 95 | Console.WriteLine(); 96 | watch.Restart(); 97 | context.Users.Insert(obj, returnIdentity: false); 98 | Console.WriteLine("Insert Without Return Identity - {0}ms", watch.ElapsedMilliseconds); 99 | 100 | Console.WriteLine(); 101 | watch.Restart(); 102 | context.Users.Insert(obj, propertyKey: "User_Id"); 103 | Console.WriteLine("Insert With Change PropertyKey - {0}ms", watch.ElapsedMilliseconds); 104 | } 105 | Console.WriteLine(); 106 | } 107 | 108 | public static void Update() 109 | { 110 | using (TestEntities context = new TestEntities()) 111 | { 112 | var obj = new 113 | { 114 | Gender = Gender.Male 115 | }; 116 | 117 | watch.Restart(); 118 | context.Users.Update(obj); 119 | Console.WriteLine("Update All - {0}ms", watch.ElapsedMilliseconds); 120 | 121 | Console.WriteLine(); 122 | watch.Restart(); 123 | context.Users.Update(new 124 | { 125 | Gender = Gender.Female 126 | }, o=> o.Id == 1); 127 | Console.WriteLine("Update With Query - {0}ms", watch.ElapsedMilliseconds); 128 | 129 | Console.WriteLine(); 130 | watch.Restart(); 131 | context.Users.Update(new 132 | { 133 | Gender = Gender.Female 134 | }, o => o.Id == 1 && (o.Name == "teste" || o.DateCreate > DateTime.Now)); 135 | Console.WriteLine("Update With Complex Query - {0}ms", watch.ElapsedMilliseconds); 136 | } 137 | Console.WriteLine(); 138 | } 139 | 140 | public static void Delete() 141 | { 142 | using (TestEntities context = new TestEntities()) 143 | { 144 | watch.Restart(); 145 | context.BlogPosts.Delete(); 146 | Console.WriteLine("Delete All - {0}ms", watch.ElapsedMilliseconds); 147 | 148 | Console.WriteLine(); 149 | watch.Restart(); 150 | context.Users.Delete(o => o.Id == 6); 151 | Console.WriteLine("Delete With Query - {0}ms", watch.ElapsedMilliseconds); 152 | } 153 | Console.WriteLine(); 154 | } 155 | 156 | public static void Select() 157 | { 158 | using (TestEntities context = new TestEntities()) 159 | { 160 | watch.Restart(); 161 | var result = context.Users.Query(o => o.Id > 1, 2, orderBy => orderBy.Asc(o => o.Id ).Desc(o => o.Name)); 162 | int qtd = result.Count(); 163 | Console.WriteLine("Select - {0}ms", watch.ElapsedMilliseconds); 164 | 165 | watch.Restart(); 166 | var result2 = context.Users.Query(o=> new { o.Id, o.Name }, o => o.Id > 1, 2, orderBy => orderBy.Asc(o => o.Id).Desc(o => o.Name)); 167 | qtd = result2.Count(); 168 | Console.WriteLine("Select With Selector - {0}ms", watch.ElapsedMilliseconds); 169 | } 170 | Console.WriteLine(); 171 | } 172 | 173 | public static void ToDapper() 174 | { 175 | using(TestEntities context = new TestEntities()) 176 | { 177 | object result = null; 178 | watch.Restart(); 179 | result = (from o in context.Users 180 | where o.Id > 1 181 | orderby o.Id 182 | select o).ToDapper().ToList(); 183 | Console.WriteLine("ToDapper - {0}ms", watch.ElapsedMilliseconds); 184 | } 185 | } 186 | #endregion 187 | 188 | #region Tests Dapper 189 | public static void InsertDapper() 190 | { 191 | using (TestEntities context = new TestEntities()) 192 | { 193 | var obj = new 194 | { 195 | Name = "User Insert", 196 | DateCreate = DateTime.Now, 197 | Gender = Gender.Female 198 | }; 199 | 200 | watch.Restart(); 201 | context.Database.Connection.Query("insert into [user] (name, datecreate, gender) values (@Name, @DateCreate, @Gender); SELECT CAST(SCOPE_IDENTITY() as bigint)", obj).FirstOrDefault(); 202 | Console.WriteLine("Insert - {0}ms", watch.ElapsedMilliseconds); 203 | } 204 | Console.WriteLine(); 205 | } 206 | 207 | public static void UpdateDapper() 208 | { 209 | using (TestEntities context = new TestEntities()) 210 | { 211 | var obj = new 212 | { 213 | Gender = Gender.Male, 214 | Id = 1, 215 | Name = "teste", 216 | Date = DateTime.Now 217 | }; 218 | 219 | watch.Restart(); 220 | context.Database.Connection.Execute("update [user] set Gender = @Gender", obj); 221 | Console.WriteLine("Update All - {0}ms", watch.ElapsedMilliseconds); 222 | 223 | Console.WriteLine(); 224 | watch.Restart(); 225 | context.Database.Connection.Execute("update [user] set Gender = @Gender where Id = @Id", obj); 226 | Console.WriteLine("Update With Query - {0}ms", watch.ElapsedMilliseconds); 227 | 228 | Console.WriteLine(); 229 | watch.Restart(); 230 | context.Database.Connection.Execute("update [user] set Gender = @Gender where Id = @Id and (name = @Name or datecreate > @Date)", obj); 231 | Console.WriteLine("Update With Complex Query Dapper - {0}ms", watch.ElapsedMilliseconds); 232 | } 233 | Console.WriteLine(); 234 | } 235 | 236 | public static void DeleteDapper() 237 | { 238 | using (TestEntities context = new TestEntities()) 239 | { 240 | watch.Restart(); 241 | context.Database.Connection.Execute("delete from [BlogPost]"); 242 | Console.WriteLine("Delete All - {0}ms", watch.ElapsedMilliseconds); 243 | 244 | Console.WriteLine(); 245 | watch.Restart(); 246 | context.Database.Connection.Execute("delete from [BlogPost] where id = 6"); 247 | Console.WriteLine("Delete With Query - {0}ms", watch.ElapsedMilliseconds); 248 | } 249 | Console.WriteLine(); 250 | } 251 | 252 | public static void SelectDapper() 253 | { 254 | using (TestEntities context = new TestEntities()) 255 | { 256 | watch.Restart(); 257 | var result = context.Database.Connection.Query("select top 2 * from [user] where id > 1 order by id"); 258 | Console.WriteLine("Select - {0}ms", watch.ElapsedMilliseconds); 259 | } 260 | Console.WriteLine(); 261 | } 262 | #endregion 263 | 264 | #region Tests EntityFramework 265 | public static void InsertEF() 266 | { 267 | using (TestEntities context = new TestEntities()) 268 | { 269 | watch.Restart(); 270 | context.Users.Add(new User() { Name = "User Insert", DateCreate = DateTime.Now, Gender = Gender.Female }); 271 | context.SaveChanges(); 272 | Console.WriteLine("Insert - {0}ms", watch.ElapsedMilliseconds); 273 | } 274 | Console.WriteLine(); 275 | } 276 | 277 | public static void UpdateEF() 278 | { 279 | using (TestEntities context = new TestEntities()) 280 | { 281 | User user = new User 282 | { 283 | Gender = Gender.Male, 284 | Id = 1, 285 | Name = "teste", 286 | DateCreate = DateTime.Now 287 | }; 288 | 289 | watch.Restart(); 290 | context.Entry(user).State = System.Data.Entity.EntityState.Modified; 291 | context.SaveChanges(); 292 | Console.WriteLine("Update All - {0}ms", watch.ElapsedMilliseconds); 293 | } 294 | Console.WriteLine(); 295 | } 296 | #endregion 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /Test/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Test")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Test")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("56576aaf-be60-4404-80e0-726a6ac21909")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Test/Test.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {65A076AA-3E50-4A39-AAAB-16CCC9BE694E} 8 | Exe 9 | Properties 10 | Test 11 | Test 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\..\..\..\Packages\Dapper.1.42\lib\net45\Dapper.dll 37 | True 38 | 39 | 40 | ..\..\..\..\Packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll 41 | True 42 | 43 | 44 | ..\..\..\..\Packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll 45 | True 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | TestContext.tt 61 | 62 | 63 | TestContext.tt 64 | 65 | 66 | TestContext.tt 67 | 68 | 69 | 70 | TestContext.tt 71 | 72 | 73 | True 74 | True 75 | TestContext.Context.tt 76 | 77 | 78 | True 79 | True 80 | TestContext.tt 81 | 82 | 83 | True 84 | True 85 | TestContext.edmx 86 | 87 | 88 | TestContext.tt 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | EntityModelCodeGenerator 97 | TestContext.Designer.cs 98 | 99 | 100 | TextTemplatingFileGenerator 101 | TestContext.edmx 102 | TestContext.Context.cs 103 | 104 | 105 | TestContext.edmx 106 | 107 | 108 | TextTemplatingFileGenerator 109 | TestContext.edmx 110 | TestContext.cs 111 | 112 | 113 | 114 | 115 | 116 | {d10801ff-2c63-4180-bfd9-a92bfcf9e2f8} 117 | Dapper.EntityFramework.Extensions 118 | 119 | 120 | 121 | 122 | 123 | 124 | 131 | -------------------------------------------------------------------------------- /Test/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | --------------------------------------------------------------------------------