Saturday, November 28, 2009

LINQ to SQL with AutoMapper

So remember my first post about LINQ to SQL? Well, I think I found a HUGE improvement over the mapping files thanks to Jimmy Bogard's AutoMapper. Take a look:

So I created a really simple domain model that looks like this:

After I created my domain model, I created a implementation project with a simple repository and a DBML file, which looks like this:




The repository code looks like this:

    public class PhotoRepository : IDisposable 
{
private readonly PhotosDataContext _dc;
public PhotoRepository()
{
Registry.
AutoMapperRegistry.Configure();
_dc =
new PhotosDataContext();
}

public List<Photo> GetAll()
{
return Mapper.Map<PhotoDataModel[], Photo[]>(_dc.PhotoDataModels.ToArray()).ToList();
}

public void Save(Photo photo)
{
Registry.
AutoMapperRegistry.Configure();
using (var dc = new PhotosDataContext())
{
dc.PhotoDataModels.InsertOnSubmit(
Mapper.Map<Photo, PhotoDataModel>(photo));
dc.SubmitChanges();
}
}

public void Dispose()
{
if (_dc != null)
_dc.Dispose();
}
}

So in the implementation project, I added my AutoMapper configuration. I setup two profiles one for the LINQtoSQL and then one to reverse it. Here's that code:

    public class AutoMapperRegistry
{
public static void Configure()
{
Mapper.Initialize(x =>
{
x.AddProfile<
LinqToSqlProfile>();
x.AddProfile<
LinqToSqlReverseProfile>();
});
}
}
    public class LinqToSqlProfile : Profile
{
protected override string ProfileName
{
get
{
return "LinqToSqlProfile";
}
}

protected override void Configure()
{
Mapper.CreateMap<PhotoDataModel, Photo>()
.ForMember(dest => dest.Photographer, opt => opt.MapFrom(src=>src.PhotographerDataModel));

Mapper.CreateMap<PhotographerDataModel, Photographer>();
}
}
    public class LinqToSqlReverseProfile:Profile
{
protected override string ProfileName
{
get
{
return "LinqToSqlReverseProfile";
}
}

protected override void Configure()
{
Mapper.CreateMap<Photo, PhotoDataModel>()
.ForMember(dest => dest.PhotographerDataModel, opt => opt.MapFrom(src => src.Photographer));

Mapper.CreateMap<Photographer, PhotographerDataModel>();
}
}

You'll notice in my repository I call the configure method twice once in the constructor and again on the save. I didn't have to do it in the save, but the way I did the console app, it was required. I could've called it before calling the save, but I wanted it all in one place to make it a little easier to read...I think it is anyhow.

So in order to flatten out my domain model like Headspring seems to practice and I try to mimic everything they do because lets face it, they're the best software company in the world. At least that's my opinion. So here is my view model:

    public class PhotoViewModel
{
public string Name { get; set; }
public string FileSize { get; set; }
public DateTime DateTaken { get; set; }
public string Description { get; set; }
public string PhotographerName { get; set; }
}

Here is my AutoMapper configuration for the UI project:

    public class ViewProfile:Profile
{
protected override string ProfileName
{
get{ return "ViewProfile"; }
}

protected override void Configure()
{
Mapper.CreateMap<Core.Photo, PhotoViewModel>()
.ForMember(dest => dest.PhotographerName, opt => opt.MapFrom(src => src.Photographer.Name));
}
}

Here's the initialization:

    public class AutoMapperRegistry
{
public static void Configure()
{
Mapper.Initialize(x => x.AddProfile<ViewProfile>());
}
}

Finally, here is my UI code that displays a list of the photographers and then saves a new one.

        static void Main(string[] args)
{
var pr = new PhotoRepository();
var photos = pr.GetAll();

AutoMapperRegistry.Configure();
foreach (var p in photos)
{
var photo = Mapper.Map<Photo, PhotoViewModel>(p);
Console.WriteLine("Photographer: " + photo.PhotographerName);
}
Console.Read();

var p1 = new Photo();
p1.Id =
Guid.NewGuid();
p1.Name =
"Test Photo";
p1.Photographer.Id =
Guid.NewGuid();
p1.Photographer.Name =
"John Smith";
p1.DateTaken =
DateTime.Now;
pr.Save(p1);
}


Download Source Here

Hopefully Jimmy reads this post and lets me know if there is anything messed up or anything that I'm not doing correctly with my mappings.

kick it on DotNetKicks.com

blog comments powered by Disqus
Related Posts Plugin for WordPress, Blogger...