Created
September 28, 2014 13:51
-
-
Save ahmad2x4/90d341b36f94325d596e to your computer and use it in GitHub Desktop.
Blog Automapper Extensions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.ComponentModel.DataAnnotations; | |
using System.ComponentModel.DataAnnotations.Schema; | |
using System.Configuration; | |
using System.Data.Entity; | |
using System.Data.SqlClient; | |
using System.Diagnostics; | |
using System.Linq; | |
using System.Linq.Expressions; | |
using System.Reflection; | |
using AutoMapper; | |
using AutoMapper.QueryableExtensions; | |
using AutomapperQuesriableTest.Properties; | |
using MongoDB.Driver; | |
using MongoRepository; | |
using Ploeh.AutoFixture; | |
using Xunit; | |
namespace AutomapperQuesriableTest | |
{ | |
public class Source | |
{ | |
public string FullName { get; set; } | |
public int NumberOfYears { get; set; } | |
} | |
public class Destination : Entity | |
{ | |
[NotMapped] | |
public override string Id { get; set; } | |
[Key] | |
public int UserId { get; set; } | |
public string Name { get; set; } | |
public int Age { get; set; } | |
} | |
public interface IRepository<TI, TO> | |
{ | |
void Add(TI obj); | |
IQueryable<TO> Find(Expression<Func<TI, bool>> predicate); | |
} | |
public class SourceRepositorySql : IRepository<Source, Destination>, IDisposable | |
{ | |
private readonly MyContext _context; | |
public SourceRepositorySql(MyContext context) | |
{ | |
_context = context; | |
} | |
public void Add(Source source) | |
{ | |
_context.Users.Add(Mapper.Map<Destination>(source)); | |
} | |
public IQueryable<Destination> Find(Expression<Func<Source, bool>> predicate) | |
{ | |
Expression<Func<Destination, Source>> mapper = Mapper.Engine.CreateMapExpression<Destination, Source>(); | |
Expression<Func<Destination, bool>> mappedSelector = predicate.Compose(mapper); | |
return _context.Users.Where(mappedSelector); | |
} | |
private bool _disposed; | |
protected virtual void Dispose(bool disposing) | |
{ | |
if (!_disposed) | |
{ | |
if (disposing) | |
{ | |
_context.Dispose(); | |
} | |
} | |
_disposed = true; | |
} | |
public void Dispose() | |
{ | |
Dispose(true); | |
GC.SuppressFinalize(this); | |
} | |
} | |
public class SourceRepositoryMongo : IRepository<Source, Destination> | |
{ | |
private readonly MongoRepository<Destination> _mongoRepository; | |
public SourceRepositoryMongo() | |
{ | |
_mongoRepository = new MongoRepository<Destination>(); | |
} | |
public void Add(Source obj) | |
{ | |
_mongoRepository.Add(Mapper.Map<Destination>(obj)); | |
} | |
public IQueryable<Destination> Find(Expression<Func<Source, bool>> predicate) | |
{ | |
Expression<Func<Destination, Source>> mapper = Mapper.Engine.CreateMapExpression<Destination, Source>(); | |
Expression<Func<Destination, bool>> mappedSelector = predicate.Compose(mapper); | |
return _mongoRepository.Where(mappedSelector); | |
} | |
public IQueryable<Destination> Find(Expression<Func<Destination, bool>> predicate) | |
{ | |
return _mongoRepository.Where(predicate); | |
} | |
} | |
public class MyContext : DbContext | |
{ | |
public MyContext(string nameOrConnectionString) : base(nameOrConnectionString) { } | |
public DbSet<Destination> Users { get; set; } | |
} | |
public class AutomapperQueriableTest | |
{ | |
public AutomapperQueriableTest() | |
{ | |
Mapper.CreateMap<Source, Destination>() | |
.ForMember(d => d.Name, opt => opt.MapFrom(s => s.FullName)) | |
.ForMember(d => d.Age, opt => opt.MapFrom(s => s.NumberOfYears)); | |
Mapper.CreateMap<Destination, Source>() | |
.ForMember(d => d.FullName, opt => opt.MapFrom(s => s.Name)) | |
.ForMember(d => d.NumberOfYears, opt => opt.MapFrom(s => s.Age)); | |
} | |
[Fact] | |
public void SimpleMappingTest() | |
{ | |
var fixture = new Fixture(); | |
var source = fixture.Create<Source>(); | |
var destination = Mapper.Map<Destination>(source); | |
Assert.Equal(source.FullName, destination.Name); | |
Assert.Equal(source.NumberOfYears, destination.Age); | |
} | |
[Fact] | |
[UseDatabase] | |
public void ShouldConvertPredicates() | |
{ | |
var connStr = ConfigurationManager.ConnectionStrings["SQLExpressConnection"].ConnectionString; | |
var myContext = new MyContext(connStr); | |
using (var repository = new SourceRepositorySql(myContext)) | |
{ | |
AddRecords(repository); | |
myContext.SaveChanges(); | |
const string name = "Ahmadreza"; | |
var query = repository.Find(s => s.FullName == name && s.NumberOfYears > 10); | |
var result = query.Project().To<Source>().ToList(); | |
Assert.Equal(1, result.Count); | |
Assert.Equal(name, result.First().FullName); | |
} | |
} | |
private static void AddRecords(IRepository<Source, Destination> repository) | |
{ | |
repository.Add(new Source { FullName = "Ahmadreza", NumberOfYears = 35 }); | |
repository.Add(new Source { FullName = "Ahmadreza", NumberOfYears = 9 }); | |
repository.Add(new Source { FullName = "Jon", NumberOfYears = 20 }); | |
} | |
[Fact] | |
[UseMongo] | |
public void MongoTest() | |
{ | |
var repositoryMongo = new SourceRepositoryMongo(); | |
AddRecords(repositoryMongo); | |
var name = "Ahmadreza"; | |
var query = repositoryMongo.Find(s => s.Name == name && s.Age > 10); | |
//var query = repositoryMongo.Find(s => s.FullName == "ahmadreza" && s.NumberOfYears > 10); | |
var result = query.Project().To<Source>(); | |
Assert.Equal(1, result.Count()); | |
Assert.Equal(name, result.First().FullName); | |
} | |
} | |
public class UseMongoAttribute : BeforeAfterTestAttribute | |
{ | |
private static void DropDatabase() | |
{ | |
const string connectionString = "mongodb://localhost"; | |
var client = new MongoClient(connectionString); | |
var server = client.GetServer(); | |
server.DropDatabase("MyDatabase"); | |
} | |
public override void Before(MethodInfo methodUnderTest) | |
{ | |
DropDatabase(); | |
base.Before(methodUnderTest); | |
} | |
} | |
public class UseDatabaseAttribute : BeforeAfterTestAttribute | |
{ | |
public override void Before(MethodInfo methodUnderTest) | |
{ | |
InstallDatabase(); | |
base.Before(methodUnderTest); | |
} | |
private void InstallDatabase() | |
{ | |
Trace.WriteLine("install database"); | |
var connStr = ConfigurationManager.ConnectionStrings["SQLExpressConnection"].ConnectionString; | |
var builder = new SqlConnectionStringBuilder(connStr) { InitialCatalog = "master" }; | |
using (var conn = new SqlConnection(builder.ConnectionString)) | |
{ | |
conn.Open(); | |
using (var cmd = new SqlCommand()) | |
{ | |
cmd.Connection = conn; | |
var schemaSql = Resources.RunningDbSchema; | |
foreach (var sql in schemaSql.Split(new[] { "GO" }, StringSplitOptions.RemoveEmptyEntries)) | |
{ | |
cmd.CommandText = sql; | |
cmd.ExecuteNonQuery(); | |
} | |
} | |
} | |
} | |
public override void After(MethodInfo methodUnderTest) | |
{ | |
base.After(methodUnderTest); | |
UninstallDatabase(); | |
} | |
private void UninstallDatabase() | |
{ | |
var connStr = ConfigurationManager.ConnectionStrings["SQLExpressConnection"].ConnectionString; | |
var builder = new SqlConnectionStringBuilder(connStr) { InitialCatalog = "master" }; | |
using (var conn = new SqlConnection(builder.ConnectionString)) | |
{ | |
conn.Open(); | |
const string dropCmd = @" | |
IF Exists (SELECT name FROM master.dbo.sysdatabases where name = N'MyDatabase') | |
DROP DATABASE [MyDatabase]"; | |
using (var cmd = new SqlCommand(dropCmd, conn)) | |
{ | |
cmd.ExecuteNonQuery(); | |
} | |
} | |
} | |
} | |
public static class FunctionCompositionExtensions | |
{ | |
public static Expression<Func<TX, TY>> Compose<TX, TY, TZ>(this Expression<Func<TZ, TY>> outer, Expression<Func<TX, TZ>> inner) | |
{ | |
return Expression.Lambda<Func<TX, TY>>( | |
ParameterReplacer.Replace(outer.Body, outer.Parameters[0], inner.Body), | |
inner.Parameters[0]); | |
} | |
} | |
class ParameterReplacer : ExpressionVisitor | |
{ | |
private readonly ParameterExpression _parameter; | |
private readonly Expression _replacement; | |
private ParameterReplacer(ParameterExpression parameter, Expression replacement) | |
{ | |
_parameter = parameter; | |
_replacement = replacement; | |
} | |
public static Expression Replace(Expression expression, ParameterExpression parameter, Expression replacement) | |
{ | |
return new ParameterReplacer(parameter, replacement).Visit(expression); | |
} | |
protected override Expression VisitParameter(ParameterExpression parameter) | |
{ | |
if (parameter == _parameter) | |
{ | |
return _replacement; | |
} | |
return base.VisitParameter(parameter); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment