Compare mapped objects and validate mapping dynamically - c#

Let's consider a dynamic mapping of an anonymous type to a predefined one:
Mapper.Initialize(cfg => cfg.CreateMissingTypeMaps = true);
var dest = Mapper.Map<Dest>(new {a = 42});
I would like to ensure all Dest properties were mapped. Actual values don't matter, it can be null on anything else.
This check would be similar to Mapper.Configuration.AssertConfigurationIsValid() (it doesn't consider new type maps) performed before/after each map call.
Simple property-to-property Reflection comparison won't work because Automapper configuration should be taken into account (I mean all these nice features like automatic type conversion, flattening etc.). So the check should use Automapper API... or not?
P.S. I understand that it could significantly decrease the perfomance. The idea is to achieve a kind of code contract and enable it in dev configurations only. Any suggestions?

I think unit tests, which will test your mapping logic, will do the same job as you expecting from your "framework".
Only, instead of using Automapper straight in your code, create wrapper which you will use everywhere you need and which you will test
public static class MapperWrapper
{
public static Dest Map(object source)
{
return Mapper.Map<Dest>(source);
}
}
Unit tests will provide "code contract" for MapperWrapper.Map method and Automapper configuration. Tests will also play a role of "safe net" for developers when they "play" with Automapper configuration.
// In example used
// NUnit as test framework
// FluentAssertions as assertion framework
[TestFixture]
public class MapperWrapperTests
{
[Test]
public void Map_ShouldReturnInstanceWithCorrectValueOfAProperty()
{
var expectedA = 42;
var input = new { A = expectedA };
var actualResult = MapperWrapper.Map(input);
actualResult.A.Should().Be(expectedA);
}
// FluentAssertions framework provide "deep object graph" assertion
[Test]
public void Map_ShouldReturnInstanceWithCorrectValues()
{
var expectedResult = new Dest
{
Id = 42,
Name = "Forty-Two",
SomeAnotherType = new AnotherType { IsValid = true }
};
var input = new
{
Id = "42",
Name = "Forty-Two",
SomeAnotherType = new { IsValid = true }
};
var actualResult = MapperWrapper.Map(input);
actualResult.ShouldBeEquivalentTo(expectedResult);
}
}
By executing those tests on every build you will get feedback about is Automapper configuration correct.
Instead of using singleton MapperWrapper you can introduce abstraction of it (interface or abstract class), implements that abstraction with Automapper methods.
With abstraction your application will not depend tightly on Automapper.

What you're looking for is AutoMapper configuration validation, it does all the validations you point out. But instead of creating maps at runtime, simply create them up front (this has the added benefit of not accidentally creating invalid/incomplete/impossible maps).
Remove the CreateMissingTypeMaps = true part and create Profile types with explicit CreateMap calls to your types you want to map.

Related

Projection of single entities in EF with extension methods

I like to do projection from my entity models into my view models using extension methods. This means I dont over/under fetch for my models and it makes the code nice and readable. It makes sense that sometimes the projections may include nested models, and I want to get reuse on those sub-projections.
I want to be able to do something like the following:
ctx.People.FiltersAndThings().ToViewModels();//the project my DB Models into view models
Extension methods for actual projection
public static IQueryable<PersonModel> ToViewModels(this IQueryable<Person> entities)
{
return entities.Select(x => new PersonModel {
Me = x.Me.ToViewModel(), //this method cannot be translated into a store expression
Friends = x.Friends.AsQueryable().ToViewModels() //works fine with some magic (tm)
});
}
public static IQueryable<ProfileModel> ToViewModels(this IQueryable<Profile> entities)
{
return entities.Select(x => new ProfileModel { Name = x.Name });
}
public static ProfileModel ToViewModel(this Profile entity)
{
return new ProfileModel { Name = entity.Name };
}
When using a Queryable (eg Friends = x.Friends.AsQueryable().ToViewModels()) we can use some magic to flatten this to an expression (see https://stackoverflow.com/a/10726256/1070291, answer by #LordTerabyte) But when we are doing an assignment with a new clause (eg Me = new ProfileModel { Name = x.Me.Name }) its not an expression so if we bundle this under an extension method (eg Me = x.Me.ToViewModel()) we can't flatten this to an expression.
How does an assignment to a new object work under the scenes in EF?
Is there a way to do convertion to a new object via an extension method?
Full demo code here: https://github.com/lukemcgregor/ExtensionMethodProjection
Edit:
I now have a blog post (Composable Repositories - Nesting Extensions) and nuget package to help with nesting extension methods in linq
Take a look at this answer. It does a very similar thing what you want. Basically you would define your transformation as an Expression tree, e.g:
public static Expression<Func<Profile, ProfileModel>> ToProfileViewModel()
{
return entity => new ProfileModel { Name = entity.Name };
}
And then do invocations of this (e.g. ExpressionsHelper.ToProfileViewModel().AsQuote()(p)).
If you prefer, you can modify the visitors, to allow a nicer syntax. Something along the lines:
[ReplacementInExpressionTrees(MethodName=nameof(ExpressionsHelper.ToProfileViewModel))]
public static ProfileModel ToViewModel(this Profile profile)
{
// this implementation is only here, so that if you call the method in a non expression tree, it will still work
return ExpressionsHelper.ToProfileViewModel().Compile()(profile); // tip: cache the compiled func!
Now you need to create a visitor, that checks all method calls, and when finds a method with this attribute, it changes the whole call to ExpressionsHelper.ToProfileViewModel().AsQuote()(profile). This is as an exercise for you :)
}

Mapping entities to DTOs without duplicated code

I'm trying to get my head around this issue where I am using the Entity Framework (6) in an N-tier application. Since data from the repository (which contains all communication with the database) should be used in a higher tier (the UI, services etc), I need to map it to DTOs.
In the database, there's quite a few many-to-many relationships going on, so the datastructure can/will get complex somewhere along the line of the applications lifetime. What I stumbled upon is, that I am repeating the exact same code when writing the repository methods. An example of this is my FirmRepository which contains a GetAll() method and GetById(int firmId) method.
In the GetById(int firmId) method, I have the following code (incomplete since there's a lot more relations that needs to be mapped to DTOs):
public DTO.Firm GetById(int id)
{
// Return result
var result = new DTO.Firm();
try
{
// Database connection
using (var ctx = new MyEntities())
{
// Get the firm from the database
var firm = (from f in ctx.Firms
where f.ID == id
select f).FirstOrDefault();
// If a firm was found, start mapping to DTO object
if (firm != null)
{
result.Address = firm.Address;
result.Address2 = firm.Address2;
result.VAT = firm.VAT;
result.Email = firm.Email;
// Map Zipcode and City
result.City = new DTO.City()
{
CityName = firm.City.City1,
ZipCode = firm.City.ZipCode
};
// Map ISO code and country
result.Country = new DTO.Country()
{
CountryName = firm.Country.Country1,
ISO = firm.Country.ISO
};
// Check if this firm has any exclusive parameters
if (firm.ExclusiveParameterType_Product_Firm.Any())
{
var exclusiveParamsList = new List<DTO.ExclusiveParameterType>();
// Map Exclusive parameter types
foreach (var param in firm.ExclusiveParameterType_Product_Firm)
{
// Check if the exclusive parameter type isn't null before proceeding
if (param.ExclusiveParameterType != null)
{
// Create a new exclusive parameter type DTO
var exclusiveParameter = new DTO.ExclusiveParameterType()
{
ID = param.ExclusiveParameterType.ID,
Description = param.ExclusiveParameterType.Description,
Name = param.ExclusiveParameterType.Name
};
// Add the new DTO to the list
exclusiveParamsList.Add(exclusiveParameter);
}
}
// A lot more objects to map....
// Set the list on the result object
result.ExclusiveParameterTypes = exclusiveParamsList;
}
}
}
// Return DTO
return result;
}
catch (Exception e)
{
// Log exception
Logging.Instance.Error(e);
// Simply return null
return null;
}
}
This is just one method. The GetAll() method will then have the exact same mapping logic which results in duplicated code. Also, when more methods gets added, i.e. a Find or Search method, the same mapping needs to be copied again. This is, of course, not ideal.
I have read a lot about the famous AutoMapper framework that can map entites to/from DTOs, but since I have these many-to-many relations it quickly feels bloated with AutoMapper config code. I've also read this article, which make sense in my eyes: http://rogeralsing.com/2013/12/01/why-mapping-dtos-to-entities-using-automapper-and-entityframework-is-horrible/
Is there any other way of doing this without copy/pasting the same code over and over again?
Thanks in advance!
You can make an extension method on Entity firm (DB.Firm) like this,
public static class Extensions
{
public static DTO.Firm ToDto(this DB.Firm firm)
{
var result = new DTO.Firm();
result.Address = firm.Address;
result.Address2 = firm.Address2;
//...
return result;
}
}
Then you can convert DB.Firm object anywhere in your code like firm.ToDto();
An alternate strategy is to use a combination of the class constructor and an explicit and/or implicit conversion operator(s). It allows you to cast one user-defined entity to another entity. The feature also has the added benefit of abstracting the process out so you aren't repeating yourself.
In your DTO.Firm class, define either an explicit or implicit operator (Note: I am making assumptions about the name of your classes):
public class Firm {
public Firm(DB.Firm firm) {
Address = firm.Address;
Email = firm.Email;
City = new DTO.City() {
CityName = firm.City.City1;
ZipCode = firm.City.ZipCode;
};
// etc.
}
public string Address { get; set;}
public string Email { get; set; }
public DTO.City City { get; set; }
// etc.
public static explicit operator Firm(DB.Firm f) {
return new Firm(f);
}
}
You can then use it in your repository code like this:
public DTO.Firm GetById(int id) {
using (var ctx = new MyEntities()) {
var firm = (from f in ctx.Firms
where f.ID == id
select f).FirstOrDefault();
return (DTO.Firm)firm;
}
}
public List<DTO.Firm> GetAll() {
using (var ctx = new MyEntities()) {
return ctx.Firms.Cast<DTO.Firm>().ToList();
}
}
Here's the reference in MSDN.
About mapping: it actually does not really matter if you use Automapper or prepare you mappings completely manually in some method (extension one or as explicit casting operator as mentioned in other answers) - the point is to have it in one place for reusability.
Just remember - you used FirstOrDefault method, so you actually called the database for a Firm entity. Now, when you are using properties of this entity, especiallly collections, they will be lazy loaded. If you have a lot of them (as you suggest in your question), you may face a huge amount of additional call and it might be a problem, especcially in foreach loop. You may end up with dozen of calls and heavy performace issues just to retrieve one dto. Just rethink, if you really need to get such a big object with all its relations.
For me, your problem is much deeper and considers application architecture. I must say, I personally do not like repository pattern with Entity Framework, in addition with Unit Of Work pattern. It seems to be very popular (at least of you take a look at google results for the query), but for me it does not fit very well with EF. Of course, it's just my opinion, you may not agree with me. For me it's just building another abstraction over already implemented Unit Of Work (DbContext) and repositories (DbSet objects). I found this article very interesing considering this topic. Command/query separation way-of-doing-things seems much more elegant for me, and also it fits into SOLID rules much better.
As I said, it's just my opinion and you may or may not agree with me. But I hope it gives you some perpective here.

What is NHibernate doing to my Iesi.Collections.ISet?

I'm trying to test a service of mine that is called GetUsersForRole. It takes in a simple string and is passes this off to my RoleRepository to deal with NHibernate and get a collection of Roles with the passed in string for its RoleName. To do this, I have a Find function on my RoleRepository that calls this code:
ICriteria crit = rb.unitOfWork.Session.CreateCriteria(typeof(Entity));
crit.SetCacheable(false);
foreach (object[] criteriaItem in criteria)
{
crit.Add(Expression.Eq((string)criteriaItem[0], criteriaItem[1]));
}
return crit.List().Cast<Entity>();
So the code above will return a list of roles and within that, there is a property defined as Iesi.Collections.ISet called Users. If a given role has Users tied to it (through a many-to-many), this property is populated.
From here, I deal with the result of this Find function and get the first Role, then I use ValueInjector to map the role.Users property to an IEnumerable set. This works 100%. Here is the code that does this:
var role = _roleRepo.Find(new List<object[]>()
{
new object[] {"Name", roleName}
}).FirstOrDefault();
if (role == null)
return null;
MapperFactory.ClearMappers();
MapperFactory.AddMapper(new ISetToIEnumerable<User, UserDTO>());
var users = Mapper.Map<Iesi.Collections.ISet, IEnumerable<UserDTO>>(role.Users);
return users;
I'm using value Injector's Automapper Simulation class to deal with set mappings. This can be found here. I had to make a special Mapper to work with the Iesi.Collections.ISet to IEnumerable mappings:
public class ISetToIEnumerable<TSource, TTarget> : TypeMapper<Iesi.Collections.ISet, IEnumerable<TTarget>>
{
public override IEnumerable<TTarget> Map(Iesi.Collections.ISet source, IEnumerable<TTarget> target)
{
base.Map(source, target);
List<TTarget> entities = new List<TTarget>();
foreach (var entity in source)
{
entities.Add(Mapper.Map<TSource, TTarget>((TSource)entity));
}
target = entities.AsEnumerable();
return target;
}
}
Again, this works 100%. In the ISetToIEnumerable mapper class, the argument source comes across as Iesi.Collections.ISet {NHibernate.Collection.PersistantSet}. This is where things mess up when trying to unit test this.
I'm trying to test a successful run with this Unit Test:
[Test]
public void GetUsersForRole_success()
{
// Arrange
var roles = new List<Role>();
var role = new Role()
{
Name = "role1",
Users = {new User() {Username = "user1"}, new User() {Username = "user2"}}
};
roles.Add(role);
_mockRoleRepository.Setup(m => m.Find(It.IsAny<IList<object[]>>())).Returns(roles);
var service = GetDefaultService();
// Act
var users = service.GetUsersForRole("role1");
Assert.That(users.Count() == 2);
}
When I debug this and step into the service.GetUsersForRole("role1") call, I get my mocked data back from my mockRoleRepository. The issue here is that my role.Users property is coming back types as Iesi.Collections.HashedSet (this is how it is instantiated in my Entity Constructor for both testing and real runs with NHibernate). Now this becomes a major issue in my ISetToIEnumerable class. My source is coming across typed as Iesi.Collections.HashedSet.
I know that I will not be able to type my mock using the NHibernate.Collection.PersistantSet because of the lack of an NHibernate session instance. Does anyone have any thoughts on what is going on here and how I might be able to replicate what NHibernate is doing to my Iesi.Collections.ISet in my Arrangement of my Mock data?
If I understand you correct, you have an ISet<T> in your domain model? Why don't you use this as your source in your mapper? Why the non generic interface?
Another alternative, is that you have a general interface for both the generic and non generic interface like IEnumerable as your source in your mapper.

Loaded from another DataContext?

In my previous applications when I used linq-to-sql I would always use one class to put my linq-to-sql code in, so I would only have one DataContext.
My current application though is getting too big and I started splitting my code up in different classes (One for Customer, one for Location, one for Supplier...) and they all have their own DataContext DatabaseDesignDataContext dc = new DatabaseDesignDataContext();
Now when I try to save a contact with a location (which I got from a different DataContext) I get the following error:
"An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported."
I assume this is because I create a DataContext for every class, but I wouldn't know how to this differently?
I'm looking for any ideas, thanks.
My classes look like the following:
public class LocatieManagement
{
private static DatabaseDesignDataContext dc = new DatabaseDesignDataContext();
public static void addLocatie(locatie nieuweLocatie)
{
dc.locaties.InsertOnSubmit(nieuweLocatie);
dc.SubmitChanges();
}
public static IEnumerable<locatie> getLocaties()
{
var query = (from l in dc.locaties
select l);
IEnumerable<locatie> locaties = query;
return locaties;
}
public static locatie getLocatie(int locatie_id)
{
var query = (from l in dc.locaties
where l.locatie_id == locatie_id
select l).Single();
locatie locatie = query;
return locatie;
}
}
That happens if the entity is still attached to the original datacontext. Turn off deferred loading (dc.DeferredLoadingEnabled = false):
partial class SomeDataContext
{
partial void OnCreated()
{
this.DeferredLoadingEnabled = false;
}
}
You may also need to serialize/deserialize it once (e.g. using datacontractserializer) to disconnect it from the original DC, here's a clone method that use the datacontractserializer:
internal static T CloneEntity<T>(T originalEntity) where T : someentitybaseclass
{
Type entityType = typeof(T);
DataContractSerializer ser =
new DataContractSerializer(entityType);
using (MemoryStream ms = new MemoryStream())
{
ser.WriteObject(ms, originalEntity);
ms.Position = 0;
return (T)ser.ReadObject(ms);
}
}
This happens because you're trying to manage data from differing contexts - you will need to properly detach and attach your objects to proceed - however, I would suggest preventing the need to do this.
So, first things first: remove the data context instances from your entity classes.
From here create 'operational' classes that expose the CRUDs and whatnot to work with that specific type of entity class, which each function using a dedicated data context for that unit of work, perhaps overloading to accept a current context for when a unit of work entails subsequent operations.
I know everybody probably gets tired of hearing this, but you really should look at using Repositories for Data Access (and using the Unit of Work pattern to ensure that all of the repositories that are sharing a unit of work are using the same DataContext).
You can read up on how to do things here: Revisiting the Repository and Unit of Work Patterns with Entity Framework (the same concepts apply to LINQ to SQL as well).
Another solution I found for this is to create one parent class DataContext
public class DataContext
{
public static DatabaseDesignDataContext dc = new DatabaseDesignDataContext();
}
And let all my other classes inherit this one.
public class LocatieManagement : DataContext
{
public static void addLocatie(locatie nieuweLocatie)
{
dc.locaties.InsertOnSubmit(nieuweLocatie);
dc.SubmitChanges();
}
}
Then all the classes use the same DataContext.

AutoMapper how to avoid initialization

How do I avoid requiring code like this:
public static class BusinessLogicAutomapper
{
public static bool _configured;
public static void Configure()
{
if (_configured)
return;
Mapper.CreateMap<Post, PostModel>();
_configured = true;
}
}
in my BL assembly, and having to call Configure() from my Global.asax in my MVC application?
I mean, I expect a call like this:
public PostModel GetPostById(long id)
{
EntityDataModelContext context = DataContext.GetDataContext();
Post post = context.Posts.FirstOrDefault(p => p.PostId == id);
PostModel mapped = Mapper.Map<Post, PostModel>(post);
return mapped;
}
to Mapper.Map<TIn,TOut> to produce the mapper if it isn't in existance, instead of having to create it myself manually (I shouldn't even know about this inner working). How can I work around declaratively creating mappers for AutoMapper?
A solution that's natural to AutoMapper would be desired, but an extension or some architectural change in order to avoid this initialization would work too.
I'm using MVC 3, .NET 4, and no IoC/DI (yet, at least)
I completely misunderstood what you were trying to do in my original answer. You can accomplish what you want by implementing part of the functionality of AutoMapper using reflection. It will be of very limited utility and the more you extend it, the more like AutoMapper it will be so I'm not sure that there's any long term value to it.
I do use a small utility like what you are wanting to automate my auditing framework to copy data from a entity model to its associated audit model. I created it before I started using AutoMapper and haven't replaced it. I call it a ReflectionHelper, the below code is a modification of that (from memory) -- it only handles simple properties but can be adapted to support nested models and collections if need be. It's convention-based, assuming that properties with the same name correspond and have the same type. Properties that don't exist on the type being copied to are simply ignored.
public static class ReflectionHelper
{
public static T CreateFrom<T,U>( U from )
where T : class, new
where U : class
{
var to = Activator.CreateInstance<T>();
var toType = typeof(T);
var fromType = typeof(U);
foreach (var toProperty in toType.GetProperties())
{
var fromProperty = fromType.GetProperty( toProperty.Name );
if (fromProperty != null)
{
toProperty.SetValue( to, fromProperty.GetValue( from, null), null );
}
}
return to;
}
Used as
var model = ReflectionHelper.CreateFrom<ViewModel,Model>( entity );
var entity = ReflectionHelper.CreateFrom<Model,ViewModel>( model );
Original
I do my mapping in a static constructor. The mapper is initialized the first time the class is referenced without having to call any methods. I don't make the logic class static, however, to enhance its testability and the testability of classes using it as a dependency.
public class BusinessLogicAutomapper
{
static BusinessLogicAutomapper
{
Mapper.CreateMap<Post, PostModel>();
Mapper.AssertConfigurationIsValid();
}
}
check out Automapper profiles.
I have this setup in my Global.asax - it runs once statically so everything is setup at runtime ready to go.
I also have 1 unit test which covers all maps to check they are correct.
A good example of this is Ayendes Raccoon Blog
https://github.com/ayende/RaccoonBlog

Categories

Resources