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.
Related
Following is the action that is adding a Loan request to the database:
[HttpPost]
public ActionResult Add(Models.ViewModels.Loans.LoanEditorViewModel loanEditorViewModel)
{
if (!ModelState.IsValid)
return View(loanEditorViewModel);
var loanViewModel = loanEditorViewModel.LoanViewModel;
loanViewModel.LoanProduct = LoanProductService.GetLoanProductById(loanViewModel.LoanProductId); // <-- don't want to add to this table in database
loanViewModel.Borrower = BorrowerService.GetBorrowerById(loanViewModel.BorrowerId); //<-- don't want to add to this table in database
Models.Loans.Loan loan = AutoMapper.Mapper.Map<Models.Loans.Loan>(loanEditorViewModel.LoanViewModel);
loanService.AddNewLoan(loan);
return RedirectToAction("Index");
}
Following is the AddNewLoan() method:
public int AddNewLoan(Models.Loans.Loan loan)
{
loan.LoanStatus = Models.Loans.LoanStatus.PENDING;
_LoanService.Insert(loan);
return 0;
}
And here is the code for Insert()
public virtual void Insert(TEntity entity)
{
if (entity == null)
throw new ArgumentNullException(nameof(entity));
try
{
entity.DateCreated = entity.DateUpdated = DateTime.Now;
entity.CreatedBy = entity.UpdatedBy = GetCurrentUser();
Entities.Add(entity);
context.SaveChanges();
}
catch (DbUpdateException exception)
{
throw new Exception(GetFullErrorTextAndRollbackEntityChanges(exception), exception);
}
}
It is adding one row successfully in Loans table but it is also adding rows to LoanProduct and Borrower table as I showed in first code comments.
I checked the possibility of multiple calls to this action and Insert method but they are called once.
UPDATE
I am facing similar problem but opposite in functioning problem here: Entity not updating using Code-First approach
I think these two have same reason of Change Tracking. But one is adding other is not updating.
The following code seems a bit odd:
var loanViewModel = loanEditorViewModel.LoanViewModel;
loanViewModel.LoanProduct = LoanProductService.GetLoanProductById(loanViewModel.LoanProductId); // <-- don't want to add to this table in database
loanViewModel.Borrower = BorrowerService.GetBorrowerById(loanViewModel.BorrowerId); //<-- don't want to add to this table in database
Models.Loans.Loan loan = AutoMapper.Mapper.Map<Models.Loans.Loan>(loanEditorViewModel.LoanViewModel);
You are setting entity references on the view model, then calling automapper. ViewModels should not hold entity references, and automapper should effectively be ignoring any referenced entities and only map the entity structure being created. Automapper will be creating new instances based on the data being passed in.
Instead, something like this should work as expected:
// Assuming these will throw if not found? Otherwise assert that these were returned.
var loanProduct = LoanProductService.GetLoanProductById(loanViewModel.LoanProductId);
var borrower = BorrowerService.GetBorrowerById(loanViewModel.BorrowerId);
Models.Loans.Loan loan = AutoMapper.Mapper.Map<Models.Loans.Loan>(loanEditorViewModel.LoanViewModel);
loan.LoanProduct = loanProduct;
loan.Borrower = borrower;
Edit:
The next thing to check is that your Services are using the exact same DbContext reference. Are you using Dependency Injection with an IoC container such as Autofac or Unity? If so, make sure that the DbContext is set registered as Instance Per Request or similar lifetime scope. If the Services effectively new up a new DbContext then the LoanService DbContext will not know about the instances of the Product and Borrower that were fetched by another service's DbContext.
If you are not using a DI library, then you should consider adding one. Otherwise you will need to update your services to accept a single DbContext with each call or leverage a Unit of Work pattern such as Mehdime's DbContextScope to facilitate the services resolving their DbContext from the Unit of Work.
For example to ensure the same DbContext:
using (var context = new MyDbContext())
{
var loanProduct = LoanProductService.GetLoanProductById(context, loanViewModel.LoanProductId);
var borrower = BorrowerService.GetBorrowerById(context, loanViewModel.BorrowerId);
Models.Loans.Loan loan = AutoMapper.Mapper.Map<Models.Loans.Loan>(loanEditorViewModel.LoanViewModel);
loan.LoanProduct = loanProduct;
loan.Borrower = borrower;
LoanService.AddNewLoan(context, loan);
}
If you are sure that the services are all provided the same DbContext instance, then there may be something odd happening in your Entities.Add() method. Honestly your solution looks to have far too much abstraction around something as simple as a CRUD create and association operation. This looks like a case of premature code optimization for DRY without starting with the simplest solution. The code can more simply just scope a DbContext, fetch the applicable entities, create the new instance, associate, add to the DbSet, and SaveChanges. There's no benefit to abstracting out calls for rudimentary operations such as fetching a reference by ID.
public ActionResult Add(Models.ViewModels.Loans.LoanEditorViewModel loanEditorViewModel)
{
if (!ModelState.IsValid)
return View(loanEditorViewModel);
var loanViewModel = loanEditorViewModel.LoanViewModel;
using (var context = new AppContext())
{
var loanProduct = context.LoanProducts.Single(x => x.LoanProductId ==
loanViewModel.LoanProductId);
var borrower = context.Borrowers.Single(x => x.BorrowerId == loanViewModel.BorrowerId);
var loan = AutoMapper.Mapper.Map<Loan>(loanEditorViewModel.LoanViewModel);
loan.LoanProduct = loanProduct;
loan.Borrower = borrower;
context.SaveChanges();
}
return RedirectToAction("Index");
}
Sprinkle with some exception handling and it's done and dusted. No layered service abstractions. From there you can aim to make the action test-able by using an IoC container like Autofac to manage the Context and/or introducing a repository/service layer /w UoW pattern. The above would serve as a minimum viable solution for the action. Any abstraction etc. should be applied afterwards. Sketch out with pencil before cracking out the oils. :)
Using Mehdime's DbContextScope it would look like:
public ActionResult Add(Models.ViewModels.Loans.LoanEditorViewModel loanEditorViewModel)
{
if (!ModelState.IsValid)
return View(loanEditorViewModel);
var loanViewModel = loanEditorViewModel.LoanViewModel;
using (var contextScope = ContextScopeFactory.Create())
{
var loanProduct = LoanRepository.GetLoanProductById( loanViewModel.LoanProductId).Single();
var borrower = LoanRepository.GetBorrowerById(loanViewModel.BorrowerId);
var loan = LoanRepository.CreateLoan(loanViewModel, loanProduct, borrower).Single();
contextScope.SaveChanges();
}
return RedirectToAction("Index");
}
In my case I leverage a repository pattern that uses the DbContextScopeLocator to resolve it's ContextScope to get a DbContext. The Repo manages fetching data and ensuring that the creation of entities are given all required data necessary to create a complete and valid entity. I opt for a repository-per-controller rather than something like a generic pattern or repository/service per entity because IMO this better manages the Single Responsibility Principle given the code only has one reason to change (It serves the controller, not shared between many controllers with potentially different concerns). Unit tests can mock out the repository to serve expected data state. Repo get methods return IQueryable so that the consumer logic can determine how it wants to consume the data.
Finally with the help of the link shared by #GertArnold Duplicate DataType is being created on every Product Creation
Since all my models inherit a BaseModel class, I modified my Insert method like this:
public virtual void Insert(TEntity entity, params BaseModel[] unchangedModels)
{
if (entity == null)
throw new ArgumentNullException(nameof(entity));
try
{
entity.DateCreated = entity.DateUpdated = DateTime.Now;
entity.CreatedBy = entity.UpdatedBy = GetCurrentUser();
Entities.Add(entity);
if (unchangedModels != null)
{
foreach (var model in unchangedModels)
{
_context.Entry(model).State = EntityState.Unchanged;
}
}
_context.SaveChanges();
}
catch (DbUpdateException exception)
{
throw new Exception(GetFullErrorTextAndRollbackEntityChanges(exception), exception);
}
}
And called it like this:
_LoanService.Insert(loan, loan.LoanProduct, loan.Borrower);
By far the simplest way to tackle this is to add the two primitive foreign key properties to the Loan class, i.e. LoanProductId and BorrowerId. For example like this (I obviously have to guess the types of LoanProduct and Borrower):
public int LoanProductId { get; set; }
[ForeignKey("LoanProductId")]
public Product LoanProduct { get; set; }
public int BorrowerId { get; set; }
[ForeignKey("BorrowerId")]
public User Borrower { get; set; }
Without the primitive FK properties you have so-called independent associations that can only be set by assigning objects of which the state must be managed carefully. Adding the FK properties turns it into foreign key associations that are must easier to set. AutoMapper will simply set these properties when the names match and you're done.
Check Models.Loans.Loan?Is it a joined model of Loans table , LoanProduct and Borrower table.
You have to add
Loans lentity = new Loans()
lentity.property=value;
Entities.Add(lentity );
var lentity = new Loans { FirstName = "William", LastName = "Shakespeare" };
context.Add<Loans >(lentity );
context.SaveChanges();
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.
I am working on a program to manage my personal finances. I have an SQLite database that is storing all of the data, and I am able to load/save accounts, bills, payments, etc.
What I am looking to do, is load the account name of the associated account based on the PayeeId of each Payment. I know how to achieve this using SQL, but my data is set up using repositories. For example, I load the Payments by calling
var payments = await _paymentsRepository.LoadAllAsync();
And the LoadAllAsync() method is in RepositoryBase class, and looks like so:
public async Task<IEnumerable<TTable>> LoadAllAsync()
{
var query = _sqliteService.Conn.Table<TTable>();
var array = (await query.ToListAsync()).ToArray();
return array;
}
and is declared in the IPaymentsRepository interface like so:
Task<IEnumerable<Payment>> LoadAllAsync();
Each Payment object has a PayeeId property that links to the Payee for that Payment. The Payment itself doesn't store any of the other information about the Payee, but I would like to be able to load the PayeeName property to display with the Payment information. Is there a simple way to do this, or will I have to create a separate ViewModel to store the "hybrid" data containing both the Payment information as well as the Payee information?
EDIT
I know I can accomplish this using an extra class, for example PaymentInfo or something, and store both the Payment and Payee data, then access it like this: PaymentInfo.Payment.PaymentAmount or PaymentInfo.Payee.PayeeName, but I would have to load them in two separate queries. While this is certainly possible, I am hoping for a solution that can be accomplished in one query, which is why I am looking at using a JOIN. If I need to, I will just use LINQ, but my question is whether or not this is possible using the repository setup that I currently have.
EDIT 2
Here is the repository code. I have tried to only include the relevant pieces. Each table has its own repository. Here is the signature of the PaymentsRepository:
public class PaymentsRepository : RepositoryBase<Payment, int>, IPaymentsRepository
{
}
The RepositoryBase<> looks like this:
public abstract class RepositoryBase<TTable, TKey> : IRepository<TTable, TKey>
where TTable : IKeyedTable<TKey>, new()
{
protected readonly ISqliteService SqliteService;
protected RepositoryBase(ISqliteService sqlLiteService)
{
SqliteService = sqlLiteService;
}
public async Task<IEnumerable<TTable>> LoadAllAsync()
{
var query = SqliteService.Conn.Table<TTable>();
var array = (await query.ToListAsync()).ToArray();
return array;
}
......
}
The IRepository interface:
interface IRepository<TTable, in TKey>
where TTable : IKeyedTable<TKey>, new()
{
Task<TTable> LoadByIdAsync(TKey id);
Task<IEnumerable<TTable>> LoadAllAsync();
Task InsertAsync(TTable item);
Task UpdateAsync(TTable item);
Task DeleteAsync(TTable item);
AsyncTableQuery<TTable> Query();
}
And the ISqliteService:
public interface ISqliteService
{
SQLiteAsyncConnection Conn { get; }
Task<object> ClearLocalDb();
void Reconnect();
}
Everything is ultimately queried against that SQLiteAsyncConnection property, using the built-in SQLite methods. For example, in the LoadAllAsync() function, var query = _sqliteService.Conn.Table<TTable>(); uses this:
public AsyncTableQuery<T> Table<T> ()
where T : new ()
{
//
// This isn't async as the underlying connection doesn't go out to the database
// until the query is performed. The Async methods are on the query iteself.
//
var conn = GetConnection ();
return new AsyncTableQuery<T> (conn.Table<T> ());
}
which is located in SQLiteAsync.cs
I wasn't able to figure out a way to directly query two different tables using LINQ, but I got things working with a "hybrid" class. I just created a PaymentInfo class that has a Payment property and a Payee property, which point to the relevant data. I added a method to my PaymentsRepository that looks like this:
public async Task<IEnumerable<PaymentInfo>> LoadAllPaymentInfoAsync()
{
var payments = await SqliteService.Conn.Table<Payment>().ToListAsync();
var payees = await SqliteService.Conn.Table<Payee>().ToListAsync();
var query = from p1 in payments
join p2 in payees on p1.PayeeId equals p2.Id
select new PaymentInfo() {Payment = p1, Payee = p2};
return query;
}
I am sure that this is not necessarily the best way to accomplish this, but I thought I would share it here in case anyone comes across this page looking to do what I did.
I think you can get IQueryable<Payment> and IQueryable<Payee>, join them in LINQ, and then call .ToArray() on the result.
It will build up the query and perform it only when you actually access the data (in this case, on the ToArray() call). I believe this should generate a single query.
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.
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