I have these two methods on a service:
public Offer GetOffer(int id, string languageCode = Website.LanguageSettings.DefaultLanguageCode)
{
Entities.Offer offerEntity = _db.Offers.FirstOrDefault(offer => offer.Id == id);
if (languageCode.ToLower(CultureInfo.InvariantCulture) != Website.LanguageSettings.DefaultLanguageCode)
{
using (IDocumentSession session = store.OpenSession())
{
Translation.Offer translatedOffer = session.LuceneQuery<Translation.Offer>(Website.RavenDbSettings.Indexes.Offers)
.Where(string.Format("ObjectId:{0} AND LanguageCode:{1}", id, languageCode))
.OrderByDescending(offer => offer.Id)
.FirstOrDefault();
var offerPOCO = Mapper.DynamicMap<Translation.Offer, Offer>(translatedOffer);
offerPOCO.Id = offerEntity.Id;
return offerPOCO;
}
}
return Mapper.Map<Entities.Offer, Offer>(offerEntity);
}
And
public Hotel GetHotel(int id, string languageCode = Website.LanguageSettings.DefaultLanguageCode)
{
Entities.Hotel hotelEntity = _db.Hotels.FirstOrDefault(hotel => hotel.Id == id);
if (languageCode.ToLower(CultureInfo.InvariantCulture) != Website.LanguageSettings.DefaultLanguageCode)
{
using(IDocumentSession session = store.OpenSession())
{
Translation.Hotel translatedHotel = session.LuceneQuery<Translation.Hotel>(Website.RavenDbSettings.Indexes.Hotels)
.Where(string.Format("ObjectId:{0} AND LanguageCode:{1}", id, languageCode))
.OrderByDescending(hotel => hotel.Id)
.FirstOrDefault();
Hotel hotelPOCO = Mapper.DynamicMap<Translation.Hotel, Hotel>(translatedHotel);
hotelPOCO.Id = hotelEntity.Id;
return hotelPOCO;
}
}
return Mapper.Map<Entities.Hotel, Hotel>(hotelEntity);
}
They are exactly the same in most aspects: they take the same params, build the same query and make the same operations, the only thing that varies is the type of objects they work with and output. Besides building a method to generate the Where() param string, I can’t think of any way I can merge most (or all) of this code into a single method and then just call it from the GetOffer() and GetHotel() methods since I’ll end up with several more just like these two.
Any advice is greatly appreciated.
Edit: adding the solution so if another poor soul comes across this problem he/she can have a starting point:
private TReturn GetObject<TReturn, TEntity, TTranslation>(int id, string languageCode, string ravenDbIndex) where TEntity:EntityObject
where TTranslation:Translation.BaseTranslationObject
where TReturn:BasePOCO
{
// TODO Run more tests through the profiler
var entities = _db.CreateObjectSet<TEntity>();
var entityKey = new EntityKey(_db.DefaultContainerName + "." + entities.EntitySet.Name, "Id", id); // Sticking to the Id convention for the primary key
TEntity entity = (TEntity)_db.GetObjectByKey(entityKey);
if(languageCode.ToLower(CultureInfo.InvariantCulture) != Website.LanguageSettings.DefaultLanguageCode)
{
using(IDocumentSession session = store.OpenSession())
{
TTranslation translatedObject = session.LuceneQuery<TTranslation>(ravenDbIndex)
.Where(string.Format("ObjectId:{0} AND LanguageCode:{1}", id, languageCode))
.OrderByDescending(translation => translation.Id)
.FirstOrDefault();
TReturn poco = Mapper.DynamicMap<TTranslation, TReturn>(translatedObject);
poco.Id = id;
return poco;
}
}
return Mapper.Map<TEntity, TReturn>(entity);
}
And then I just call:
GetObject<Hotel, Entities.Hotel, Translation.Hotel>(id, languageCode, Website.RavenDbSettings.Indexes.Hotels);
Whenever I need a hotel.
Thank you all for the great replies, learned quite a lot from them.
It looks as though you could refactor this into a generic method. Something similar to this (I’m making some assumptions about the ability to refactor some method calls, etc. But hopefully you get the idea)