Skip to content

Instantly share code, notes, and snippets.

@ahmad2x4
Created September 28, 2014 13:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ahmad2x4/90d341b36f94325d596e to your computer and use it in GitHub Desktop.
Save ahmad2x4/90d341b36f94325d596e to your computer and use it in GitHub Desktop.
Blog Automapper Extensions
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