using System; using System.Collections.Generic; var list = new List<int> { 1, 2 }; foreach(var item in list) Console.Write(item);
using System; using System.Collections.Generic; var list = new List<int> { 1, 2 }; foreach(var item in list) Console.Write(item);
<img [src]='producr.imageUrl'>
<img src={{producr.imageUrl}}>
<img src='http://www.mysite.com/images/{{producr.imageUrl}}'>
<tbody> <tr *ngFor='#product of products'> <td> <img [src]='product.imageUrl' [title]='product.productName'> </td> <td>{{ product.productName }}</td> <td>{{ product.productCode }}</td> <td>{{ product.releaseDate }}</td> <td>{{ product.price }}</td> <td>{{ product.starRating }}</td> </tr> </tbody>
export class ProductListComponent { pageTitle: string = 'Product List'; imageWidth: number = 50; imageMargin: number = 2; products: any[] = [ // as before... ]; }
<tbody> <tr *ngFor='#product of products'> <td> <img [src]='product.imageUrl' [title]='product.productName' [style.width.px]='imageWidth' [style.margin.px]='imageMargin'> </td>
<button (click)='toggleImage()'>
export class ProductListComponent { pageTitle: string = 'Product List'; imageWidth: number = 50; imageMargin: number = 2; showImage: boolean = false;
export class ProductListComponent { // as before ... toggleImage(): void { this.showImage = !this.showImage; } }
<button class='btn btn-primary' (click)='toggleImage()'> Show Image </button>
<tr *ngFor='#product of products'> <td> <img *ngIf='showImage' [src]='product.imageUrl' [title]='product.productName' [style.width.px]='imageWidth' [style.margin.px]='imageMargin'> </td>
<button class='btn btn-primary' (click)='toggleImage()'> {{showImage ? 'Hide' : 'Show'}} Image </button>
<input [(ngModel)]='listFilter' >
export class ProductListComponent { pageTitle: string = 'Product List'; imageWidth: number = 50; imageMargin: number = 2; showImage: boolean = false; listFilter: string = 'cart';
<div class='panel-body'> <div class='row'> <div class='col-md-2'>Filter by:</div> <div class='col-md-4'> <input type='text' [(ngModel)]='listFilter' /> </div> </div> <div class='row'> <div class='col-md-6'> <h3>Filtered by: {{listFilter}}</h3> </div> </div>
{{ product.productCode | lowercase }}
[title]='product.productName | uppercase'
{{ product.price | currency | lowercase }}
{{ product.price | currency:'USD':true:'1.2-2' }}
<td>{{ product.productName }}</td> <td>{{ product.productCode | lowercase }}</td> <td>{{ product.releaseDate }}</td> <td>{{ product.price | currency:'USD':true:'1.2-2'}}</td> <td>{{ product.starRating }}</td>
public static IEnumerable<TResult> OfType<TResult>(this IEnumerable source)
IEnumerable input = new object[] { "Apple", 33, "Sugar", 44, 'a', new DateTime()}; IEnumerable<string> query = input.OfType<string>(); foreach (var item in query) { Console.WriteLine(item); }
Apple Sugar
class Ingredient { public string Name { get; set; } } class DryIngredient : Ingredient { public int Grams { get; set; } } class WetIngredient : Ingredient { public int Millilitres { get; set; } }
IEnumerable<Ingredient> input = new Ingredient[] { new DryIngredient { Name = "Flour" }, new WetIngredient { Name = "Milk" }, new WetIngredient { Name = "Water" } }; IEnumerable<WetIngredient> query = input.OfType<WetIngredient>(); foreach (WetIngredient item in query) { Console.WriteLine(item.Name); }
Milk Water
IEnumerable input = new object[] { "Apple", 33, "Sugar", 44, 'a', new DateTime() }; IEnumerable<string> query = input.Cast<string>(); foreach (string item in query) { Console.WriteLine(item); }
Unhandled Exception: System.InvalidCastException: Unable to cast object of type 'System.Int32' to type 'System.String'.
IEnumerable input = new object[]{ "Apple", "Sugar", "Flour" }; IEnumerable<string> query = from string i in input select i; foreach (var item in query) { Console.WriteLine(item); }
IEnumerable<string> input = new List<string> { "Apple", "Sugar", "Flour" }; string[] array = input.ToArray();
IEnumerable<string> input = new[] { "Apple", "Sugar", "Flour" }; List<string> list = input.ToList();
class Recipe { public int Id { get; set; } public string Name { get; set; } public int Rating { get; set; } } IEnumerable<Recipe> recipes = new[] { new Recipe { Id = 1, Name = "Apple Pie", Rating = 5 }, new Recipe { Id = 2, Name = "Cherry Pie", Rating = 2 }, new Recipe { Id = 3, Name = "Beef Pie", Rating = 3 } }; Dictionary<int, Recipe> dict = recipes.ToDictionary(x => x.Id); foreach (KeyValuePair<int, Recipe> item in dict) { Console.WriteLine($"Key={item.Key}, Recipe={item.Value}"); }
Key=1, Recipe=Apple Pie Key=2, Recipe=Cherry Pie Key=3, Recipe=Beef Pie
class Recipe { public int Id { get; set; } public string Name { get; set; } public byte Rating { get; set; } } IEnumerable<Recipe> recipes = new[] { new Recipe { Id = 1, Name = "Apple Pie", Rating = 5 }, new Recipe { Id = 1, Name = "Banana Pie", Rating = 5 }, new Recipe { Id = 2, Name = "Cherry Pie", Rating = 2 }, new Recipe { Id = 3, Name = "Beef Pie", Rating = 3 } }; ILookup<byte, Recipe> look = recipes.ToLookup(x => x.Rating); foreach (IGrouping<byte, Recipe> ratingGroup in look) { byte rating = ratingGroup.Key; Console.WriteLine($"Rating {rating}"); foreach (var recipe in ratingGroup) { Console.WriteLine($" - {recipe.Name}"); } }
Rating 5 - Apple Pie - Banana Pie Rating 2 - Cherry Pie Rating 3 - Beef Pie
Ingredient[] ingredients = { new Ingredient {Name = "Sugar", Calories = 500}, new Ingredient {Name = "Egg", Calories = 100}, new Ingredient {Name = "Milk", Calories = 150}, new Ingredient {Name = "Flour", Calories = 50}, new Ingredient {Name = "Butter", Calories = 500} }; Ingredient element = ingredients.First(); Console.WriteLine(element.Name);
Sugar
Ingredient[] ingredients = { new Ingredient {Name = "Sugar", Calories = 500}, new Ingredient {Name = "Egg", Calories = 100}, new Ingredient {Name = "Milk", Calories = 150}, new Ingredient {Name = "Flour", Calories = 50}, new Ingredient {Name = "Butter", Calories = 500} }; Ingredient element = ingredients.First(x=>x.Calories==150); Console.WriteLine(element.Name);
Milk
Unhandled Exception: System.InvalidOperationException: Sequence contains no elements
Ingredient[] ingredients = { }; Ingredient element = ingredients.First();
Unhandled Exception: System.InvalidOperationException: Sequence contains no matching element
Ingredient[] ingredients = { new Ingredient {Name = "Sugar", Calories = 500}, new Ingredient {Name = "Egg", Calories = 100}, new Ingredient {Name = "Milk", Calories = 150}, new Ingredient {Name = "Flour", Calories = 50}, new Ingredient {Name = "Butter", Calories = 500} }; Ingredient element = ingredients.First(x=>x.Calories==1500);
Ingredient[] ingredients = { }; Ingredient element = ingredients.FirstOrDefault(); Console.WriteLine(element == null);
True
Ingredient[] ingredients = { new Ingredient {Name = "Sugar", Calories = 500}, new Ingredient {Name = "Egg", Calories = 100}, new Ingredient {Name = "Milk", Calories = 150}, new Ingredient {Name = "Flour", Calories = 50}, new Ingredient {Name = "Butter", Calories = 500} }; Ingredient element = ingredients.FirstOrDefault(x=>x.Calories==1500); Console.WriteLine(element==null);
True
Ingredient[] ingredients = { new Ingredient {Name = "Sugar", Calories = 500}, new Ingredient {Name = "Egg", Calories = 100}, new Ingredient {Name = "Milk", Calories = 150}, new Ingredient {Name = "Flour", Calories = 50}, new Ingredient {Name = "Butter", Calories = 500} }; Ingredient element = ingredients.Last(x=>x.Calories==500); Console.WriteLine(element.Name);
Flour
Unhandled Exception: System.InvalidOperationException: Sequence contains more than one matching element Unhandled Exception: System.InvalidOperationException: Sequence contains no matching element
Ingredient[] ingredients = { new Ingredient { Name = "Sugar", Calories = 500 } }; Ingredient element = ingredients.Single(); Console.WriteLine(element.Name);
Sugar
Ingredient[] ingredients = { new Ingredient { Name = "Sugar", Calories = 500 }, new Ingredient {Name = "Butter", Calories = 150}, new Ingredient {Name = "Milk", Calories = 500} }; Ingredient element = ingredients.Single(x => x.Calories == 150); Console.WriteLine(element.Name);
Butter
Ingredient[] ingredients = { new Ingredient { Name = "Sugar", Calories = 500 }, new Ingredient {Name = "Egg", Calories = 100}, new Ingredient {Name = "Milk", Calories = 50} }; Ingredient element = ingredients.SingleOrDefault(x => x.Calories == 9999); Console.WriteLine(element==null);
True
Ingredient[] ingredients = { new Ingredient { Name = "Sugar", Calories = 500 }, new Ingredient {Name = "Egg", Calories = 100}, new Ingredient {Name = "Milk", Calories = 50} }; Ingredient element = ingredients.ElementAt(2); Console.WriteLine(element.Name);
Milk
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Ingredient[] ingredients = { new Ingredient { Name = "Sugar", Calories = 500 }, new Ingredient {Name = "Egg", Calories = 100}, new Ingredient {Name = "Milk", Calories = 50} }; Ingredient element = ingredients.ElementAtOrDefault(5); Console.WriteLine(element==null);
True
Ingredient[] ingredients = { new Ingredient { Name = "Sugar", Calories = 500 }, new Ingredient {Name = "Egg", Calories = 100}, new Ingredient {Name = "Milk", Calories = 50} }; IEnumerable<Ingredient> query = ingredients.DefaultIfEmpty(); foreach (Ingredient item in query) { Console.WriteLine(item.Name); }
Sugar Egg Milk
Ingredient[] ingredients = { }; IEnumerable<Ingredient> query = ingredients.DefaultIfEmpty(); foreach (Ingredient item in query) { Console.WriteLine(item == null); }
True
public class Party : Entity, INumberedEntity { public const int MaxFirstNameLength = 50; public const int MaxLastNameLength = 50; public const int MaxDescriptionLength = 1024; public string Number { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Description { get; set; } //... }
public class Customer : TrackableEntity, IAggregateRoot, IPassivable { public bool IsActive { get; set; } public byte[] RowVersion { get; set; } //... public Party Party { get; set; } }
public class Personnel : TrackableEntity, IAggregateRoot, IPassivable { public bool IsActive { get; set; } public byte[] RowVersion { get; set; } //... public Party Party { get; set; } }
builder.HasOne(c => c.Party).WithOne().HasForeignKey<Customer>(c => c.Id) .OnDelete(DeleteBehavior.Restrict);
builder.HasOne(p => p.Party).WithOne().HasForeignKey<Personnel>(p => p.Id) .OnDelete(DeleteBehavior.Restrict);
public static List<string> ScanAllControllers(HttpRequestBase requestBase) { if (requestBase.Url == null) return null; Assembly asm = Assembly.GetAssembly(typeof(MvcApplication)); var securedControllers = asm.GetTypes() .Where( type => typeof(IController).IsAssignableFrom(type) && Attribute.IsDefined(type, typeof(AuthorizeAttribute)) && !type.Name.StartsWith("T4MVC")); var allControllers = asm.GetTypes() .Where(type => typeof(Controller).IsAssignableFrom(type)); var controllers = allControllers.Except(securedControllers); var actionsWithAuthorizeAndAjaxAttribute = allControllers.SelectMany(t => t.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public)) .Where(m => m.GetCustomAttributes(typeof(AuthorizeAttribute), true) .Any() | m.GetCustomAttributes(typeof(AjaxRequestAttribute), true) .Any()); var controllersList = controllers.SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public)) .Except(actionsWithAuthorizeAndAjaxAttribute) .Where((returnType => returnType.ReturnType == (typeof(ViewResult)) || returnType.ReturnType == (typeof(ActionResult)))) .Where(returntype => !returntype.DeclaringType.Name.StartsWith("Site")) .Where(returnType => !returnType.DeclaringType.Name.StartsWith("Admin")) .Select( x => new { Controller = x.DeclaringType.Name.Replace("Controller", string.Empty), Action = x.Name, ReturnType = x.ReturnType.Name }) .OrderBy(x => x.Controller).ThenBy(x => x.Action).Distinct().ToList(); var url = requestBase.Url.GetLeftPart(UriPartial.Authority); return controllersList.Select(controller => $"{url}/{controller.Controller}/{controller.Action}").ToList(); }
query OwnersQuery { owners { name account { type } } }
{ "data": { "owners": [ { "name": "John Doe", "accounts": [ { "type": "Cash" }, { "type": "Savings" } ] } ] } }
dotnet new api -n ASPCoreGraphQL
پوشه Contracts شامل واسطهای مورد نیاز برای repository logic میباشد:
namespace ASPCoreGraphQL.Contracts { public interface IOwnerRepository { } }
namespace ASPCoreGraphQL.Contracts { public interface IAccountRepository { } }
public class Owner { [Key] public Guid Id { get; set; } [Required(ErrorMessage = "Name is required")] public string Name { get; set; } public string Address { get; set; } public ICollection<Account> Accounts { get; set; } } public class Account { [Key] public Guid Id { get; set; } [Required(ErrorMessage = "Type is required")] public TypeOfAccount Type { get; set; } public string Description { get; set; } [ForeignKey("OwnerId")] public Guid OwnerId { get; set; } public Owner Owner { get; set; } } public enum TypeOfAccount { Cash, Savings, Expense, Income }
public class ApplicationContext : DbContext { public ApplicationContext(DbContextOptions options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { } public DbSet<Owner> Owners { get; set; } public DbSet<Account> Accounts { get; set; } }
public class OwnerRepository : IOwnerRepository { private readonly ApplicationContext _context; public OwnerRepository(ApplicationContext context) { _context = context; } }
public class AccountRepository : IAccountRepository { private readonly ApplicationContext _context; public AccountRepository(ApplicationContext context) { _context = context; } }
public void ConfigureServices(IServiceCollection services) { services.AddDbContext<ApplicationContext>(opt => opt.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddScoped<IOwnerRepository, OwnerRepository>(); services.AddScoped<IAccountRepository, AccountRepository>(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2) .AddJsonOptions(options => options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore); }
dotnet add package GraphQL
dotnet add package GraphQL.Server.Transports.AspNetCore
dotnet add package GraphQL.Server.Ui.Playground
public class AppSchema : Schema { public AppSchema(IDependencyResolver resolver) :base(resolver) { } }
public class OwnerType : ObjectGraphType<Owner> { public OwnerType() { Field(x => x.Id, type: typeof(IdGraphType)).Description("Id property from the owner object."); Field(x => x.Name).Description("Name property from the owner object."); Field(x => x.Address).Description("Address property from the owner object."); } }
public interface IOwnerRepository { IEnumerable<Owner> GetAll(); } public class OwnerRepository : IOwnerRepository { private readonly ApplicationContext _context; public OwnerRepository(ApplicationContext context) { _context = context; } public IEnumerable<Owner> GetAll() => _context.Owners.ToList(); }
public class AppQuery : ObjectGraphType { public AppQuery(IOwnerRepository repository) { Field<ListGraphType<OwnerType>>( "owners", resolve: context => repository.GetAll() ); } }
public class AppSchema : Schema { public AppSchema(IDependencyResolver resolver) :base(resolver) { Query = resolver.Resolve<AppQuery>(); } }
public void ConfigureServices(IServiceCollection services) { ... services.AddScoped<IDependencyResolver>(s => new FuncDependencyResolver(s.GetRequiredService)); services.AddScoped<AppSchema>(); services.AddGraphQL(o => { o.ExposeExceptions = false; }) .AddGraphTypes(ServiceLifetime.Scoped); ... }
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { ... app.UseGraphQL<AppSchema>(); app.UseGraphQLPlayground(options: new GraphQLPlaygroundOptions()); app.UseMvc(); }
dotnet run
https://localhost:5001/ui/playground
return-type method-name<type-parameters>(parameters)
public T1 PrintValue<T1, T2>(T1 param1, T2 param2) { Console.WriteLine("values are: parameter 1 = " + param1 + " and parameter 2 = " + param2); return param1; }
public void MyMethod< T >() where T : struct { ... }
class C<T> where T : struct {} // value type
class D<T> where T : class {} // reference type
class H<T> where T : new() {} // no parameter constructor
public void MyMethod< T >() where T : IComparable, MyBaseClass, new () { ... }
class B {} class E<T> where T : B {} // be/derive from base class
interface I {} class G<T> where T : I {} // be/implement interface
class F<T, U> where T : U {} // be/derive from U
interface I {} class J<T> where T : class, I
interface I {} class J<T, U> where T : class, I where U : I, new() {}
//this method returns if both the parameters are equal public static bool Equals< T > (T t1, Tt2) { return (t1 == t2); }
Start > Control Panel > System > Advanced Environment Variables -> System Variables -> find PATH
C:\Program Files\Adobe\Adobe PDF iFilter 9 for 64-bit platforms\bin\
exec sys.sp_fulltext_service 'load_os_resources', 1; EXEC sp_fulltext_service 'verify_signature', 0 EXEC sp_fulltext_service 'update_languages'; -- update language list EXEC sp_fulltext_service 'restart_all_fdhosts'; -- restart daemon reconfigure with override
exec sys.sp_help_fulltext_system_components 'filter';
SELECT document_type, path from sys.fulltext_document_types where document_type = '.pdf'
CREATE TABLE PdfDocuments ( id INT IDENTITY(1,1) NOT NULL, doctype NCHAR(4) NOT NULL, doccontent VARBINARY(MAX) NOT NULL, CONSTRAINT PK_PdfDocuments PRIMARY KEY CLUSTERED(id) );
INSERT INTO PdfDocuments(doctype, doccontent) SELECT N'PDF', bulkcolumn FROM OPENROWSET (BULK 'C:\Users\Vahid\Downloads\1732-DotNetTips.pdf', SINGLE_BLOB) AS doc; INSERT INTO PdfDocuments(doctype, doccontent) SELECT N'PDF', bulkcolumn FROM OPENROWSET (BULK 'C:\Users\Vahid\Downloads\1733-DotNetTips.pdf', SINGLE_BLOB) AS doc;
-- Search property list CREATE SEARCH PROPERTY LIST PdfSearchPropertyList; GO ALTER SEARCH PROPERTY LIST PdfSearchPropertyList ADD 'Author' WITH (PROPERTY_SET_GUID = 'F29F85E0-4FF9-1068-AB91-08002B27B3D9', PROPERTY_INT_ID = 4, PROPERTY_DESCRIPTION = 'Author - author of a given item.'); GO
CREATE FULLTEXT STOPLIST SQLStopList; GO -- Add a stopwords ALTER FULLTEXT STOPLIST SQLStopList ADD N'به' LANGUAGE 'English'; ALTER FULLTEXT STOPLIST SQLStopList ADD N'با' LANGUAGE 'English'; --.....
-- Full-text catalog CREATE FULLTEXT CATALOG PdfDocumentsFtCatalog; GO -- Full-text index CREATE FULLTEXT INDEX ON PdfDocuments ( [doccontent] TYPE COLUMN [doctype] Language 1033 STATISTICAL_SEMANTICS ) KEY INDEX PK_PdfDocuments ON PdfDocumentsFtCatalog WITH STOPLIST = SQLStopList, SEARCH PROPERTY LIST = PdfSearchPropertyList, CHANGE_TRACKING AUTO; GO
SELECT I.document_id, I.display_term, I.occurrence_count FROM sys.dm_fts_index_keywords_by_document(DB_ID(DB_NAME()), OBJECT_ID(N'dbo.PdfDocuments')) AS I INNER JOIN dbo.PdfDocuments D ON D.id = I.document_id;
SELECT * FROM PdfDocuments WHERE CONTAINS(doccontent, N'است') SELECT I.document_id, I.display_term, I.property_id FROM sys.dm_fts_index_keywords_by_property(DB_ID(DB_NAME()), OBJECT_ID(N'dbo.PdfDocuments')) AS I INNER JOIN dbo.PdfDocuments D ON D.id = I.document_id;
public async Task<IHttpActionResult> LoginUserAsync(LoginUserBindingModel model) { var requestParams = new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("grant_type", "password"), new KeyValuePair<string, string>("username", model.Username), new KeyValuePair<string, string>("password", model.Password) }; var requestParamsFormUrlEncoded = new FormUrlEncodedContent(requestParams); using (var client = new HttpClient()) { client.BaseAddress = new Uri("http://localhost:9577/"); client.DefaultRequestHeaders.Accept.Clear(); // client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); var response = await client.PostAsync("/login", requestParamsFormUrlEncoded); if (response.StatusCode == HttpStatusCode.OK) { var responseString = await response.Content.ReadAsStringAsync(); var jsSerializer = new JavaScriptSerializer(); var responseData = jsSerializer.Deserialize<Dictionary<string, string>>(responseString); return Content(HttpStatusCode.OK, responseData); } else { return BadRequest(response.ToString()); } } }
using System.Collections.Generic; namespace AutoMapperComparison.Models { public class User { public int Id { get; set; } public string Name { get; set; } public ICollection<Address> Addresses { get; set; } } }
using System.ComponentModel.DataAnnotations.Schema; namespace AutoMapperComparison.Models { public class Address { public int Id { get; set; } public double? Code { get; set; } public string Title { get; set; } public int UserId { get; set; } [ForeignKey(nameof(UserId))] public virtual User User { get; set; } } }
using EntityFramework.BulkInsert.Extensions; using System.Collections.Generic; using System.Data.Entity; using System.Data.SqlClient; namespace AutoMapperComparison.Models { public class AppDbContextInitializer : DropCreateDatabaseAlways<AppDbContext> { protected override void Seed(AppDbContext context) { User user = context.Users.Add(new User { Name = "Test" }); context.SaveChanges(); List<Address> addresses = new List<Address>(); for (int i = 0; i < 500000; i++) { addresses.Add(new Address { Id = i, Code = 1, Title = "Test", UserId = user.Id }); } context.BulkInsert(addresses); base.Seed(context); } } public class AppDbContext : DbContext { static AppDbContext() { Database.SetInitializer(new AppDbContextInitializer()); //Database.SetInitializer<AppDbContext>(null); } public AppDbContext() : base(new SqlConnection(@"Data Source=.;Initial Catalog=AppDbContext;Integrated Security=True"), contextOwnsConnection: true) { Configuration.AutoDetectChangesEnabled = false; Configuration.EnsureTransactionsForFunctionsAndCommands = false; Configuration.LazyLoadingEnabled = false; Configuration.ProxyCreationEnabled = false; Configuration.ValidateOnSaveEnabled = false; Configuration.UseDatabaseNullSemantics = false; } public DbSet<User> Users { get; set; } public DbSet<Address> Addresses { get; set; } } }
namespace AutoMapperComparison.Models { public class AddressDto { public int Id { get; set; } public double? Code { get; set; } public string Title { get; set; } public int UserId { get; set; } public string UserName { get; set; } } }
using AutoMapper; using AutoMapper.QueryableExtensions; using AutoMapperComparison.Models; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; namespace AutoMapperComparison { public class Program { public static void Main() { Mapper.Initialize(cfg => { cfg.CreateMap<Address, AddressDto>(); }); Console.WriteLine($"Create Db {DateTimeOffset.UtcNow}"); using (AppDbContext db = new AppDbContext()) { db.Database.Initialize(force: true); db.Database.ExecuteSqlCommand("DBCC DROPCLEANBUFFERS"); //Removes all clean buffers from the buffer pool, and columnstore objects from the columnstore object pool Console.WriteLine(db.Addresses.ProjectTo<AddressDto>()); Console.WriteLine(db.Addresses.Select(add => new AddressDto { Id = add.Id, Code = add.Code, Title = add.Title, UserId = add.UserId, UserName = add.User.Name })); } Console.WriteLine($"Normal Select {DateTimeOffset.UtcNow}"); using (AppDbContext db = new AppDbContext()) { db.Database.ExecuteSqlCommand("DBCC DROPCLEANBUFFERS"); Stopwatch watch = Stopwatch.StartNew(); List<AddressDto> addresses = db.Addresses.AsNoTracking().Select(add => new AddressDto { Id = add.Id, Code = add.Code, Title = add.Title, UserId = add.UserId, UserName = add.User.Name }).ToList(); List<AddressDto> addresses2 = db.Addresses.AsNoTracking().Select(add => new AddressDto { Id = add.Id, Code = add.Code, Title = add.Title, UserId = add.UserId, UserName = add.User.Name }).ToList(); watch.Stop(); Console.WriteLine($"{watch.ElapsedMilliseconds} {addresses.Count} {addresses2.Count}"); } Console.WriteLine($"AutoMapper Exec {DateTimeOffset.UtcNow}"); using (AppDbContext db = new AppDbContext()) { db.Database.ExecuteSqlCommand("DBCC DROPCLEANBUFFERS"); Stopwatch watch = Stopwatch.StartNew(); List<AddressDto> addresses = db.Addresses.AsNoTracking().ProjectTo<AddressDto>().ToList(); List<AddressDto> addresses2 = db.Addresses.AsNoTracking().ProjectTo<AddressDto>().ToList(); watch.Stop(); Console.WriteLine($"{watch.ElapsedMilliseconds} {addresses.Count} {addresses2.Count}"); } Console.ReadKey(); } } }
حال نتایج بدست آمده، در قسمت پایینتر آن نمایان میشود:
البته نتیجهی این آزمایش بسته به سخت افزار سیستم شما ممکن است کمی متفاوت باشد.
در سه آزمایش دیگر به صورت متوالی نتیجهی زیر بدست آمد:
Normal | AutoMapper |
2451 | 2378 |
2120 | 2111 |
2202 | 2124 |
اگر این مقدار جزئی از تفاوت بین دو نوع مختلف آزمایش را مورد نظر نگیریم، میتوان گفت که هر دو روش نتیجهی کاملا یکسانی خواهند داشت. فقط با استفاده از AutoMapper کدهای کمتری نوشته شدهاست!
اما دلیل چیست؟ از آنجایی که ProjectTo از Dto به Model انجام شده و Lambda Expressionی که به سمت Entity Framework فرستاده شدهاست با روش Normal کاملا برابر است و بقیهی عملیات توسط EF انجام میشود، با قاطعیت میتوان گفت که هر دو روش ذکر شده از نظر Performance کاملا یکسان خواهند بود.
نکته: البته به این موضوع باید توجه شود که اگر همین آزمایش را بطور مثال با استفاده از یک Listی از رکوردهای درون Memory ساخته شده توسط خودمان انجام دهیم، آن موقع نتیجهی یکسانی نخواهیم داشت، به دلیل اینکه EFی دیگر وجود نخواهد داشت که مسئولیت بازگشت دادهها را بر عهده بگیرد. از آنجائیکه اکثر کارهایی که توقع داریم AutoMapper برای ما انجام دهد، توسط ORM بازگشت داده میشود، پس میتوان گفت نکتهی فوق تقریبا در دنیای واقعی رخ نخواهد داد و باعث مشکل نخواهد شد.