I need to implement a pluggable system where Automapper profiles can be provided by many DLL.
The object to be mapped has a list of persons:
public class CompanySrc
{
public List<PersonSrc> Persons {get;set;}
}
public class CompanyDest
{
public List<PersonDest> Persons {get;set;}
}
PersonSrc and PersonDest are abstract classes that can be extended in each DLL:
DLL1:
public class EmployeeSrc : PersonSrc
{
...
}
public class EmployeeDest : PersonDest
{
...
}
DLL2:
public class ManagerSrc : PersonSrc
{
...
}
public class ManagerDest : PersonDest
{
...
}
The idea was to implement something similar to this:
public class DLL1Profile : Profile
{
public DLL1Profile()
{
CreateMap<PersonSrc, PersonDest>()
.Include<EmployeeSrc, EmployeeDest>();
CreateMap<EmployeeSrc, EmployeeDest>();
}
}
public class DLL2Profile : Profile
{
public DLL2Profile()
{
CreateMap<PersonSrc, PersonDest>()
.Include<ManagerSrc, ManagerDest>();
CreateMap<ManagerSrc, ManagerDest>();
}
}
Mapping is done in the following way
var mc = new MapperConfiguration(cfg =>
{
cfg.CreateMap<CompanySrc, CompanyDest>()
cfg.AddProfile(new DLL1Profile());
cfg.AddProfile(new DLL2Profile ());
});
IMapper sut = mc.CreateMapper();
var result = sut.Map<CompanyDest>(companySrc);
but this approach is not working. When the "People" list contains an Employee and a Manager, and I try to map the whole list I get an exception.
Any suggestion?
You are seeing this problem because you have multiple calls to CreateMap<PersonSrc, PersonDest>() - only one mapping can exist.
When you are extending your base class in different DLLs, don't use .Include, use .IncludeBase instead. Include requires that the profile including your base class is able to reference the derived class, which is most likely not what you want to happen.
You should define your base mapping somewhere common, presumably where Person is defined:
CreateMap<PersonSrc, PersonDest>();
In your DLL1 profile etc, use IncludeBase instead:
CreateMap<ManagerSrc, ManagerDest>()
.IncludeBase<PersonSrc, PersonDest>();
Related
I have the requirement to be able to perform many conversions of external models to my own internal models.
I have decided to apply the Adapter pattern, but I want to make it as generic as possible. So effectively, I want it to be handle both "single" POCO's, but if i need to pass/adapt a collection then this also must work eg:
IEnumerable<IAdaptee> OR IList<TAdaptee>
and return my own adapted object(s):
IEnumerable<IAdapted> OR IList<TAdapted>
I want to do something like the following:
public interface IGenericAdapter
{
TAdapted Adapt<TAdapted,TAdaptee>(TAdaptee adaptee);
}
Where I am coming unstuck is when I build my "Adapter" class, and then implement the above interface, I am getting constraint mismatch errors. This of course, makes sense, because If i am applying constraints to the classes which implement the interface, and the interface doesn't have them, then of course errors occur.
So:
public class AToBAdapter
{
public TAdapted Adapt<TAdapted,TAdaptee>(TAdaptee adaptee)
where TAdapted: IList<FooAdapted>
where TAdaptee: IList<FooAdaptee>
{
// I want my constraints to be active here, as I need to perform specific operations here
}
}
The above works fine in and of itself, which is fine. But I want to hide all this behind a generic interface that I can use whenever it suits.
Of course, Once i add this it fails due to no constraints on the interface, yet constraints on the implementing class.
public class AToBAdapter:IAdapterGeneric
What's the magic bullet here which will enable me to build a truly generic Adapter - I'm guessing certain constraints on the interface? casting? but need assistance on the best course of action.
Thanks,
Chud
If you have access to your external models, you could use an interface as a marker:
public interface IAdaptee { }
public interface IAdapted { }
And use those interfaces as your adapter interface constraints:
public interface IGenericAdapter<out TAdapted, in TAdaptee>
where TAdaptee : IAdaptee
where TAdapted : IAdapted
{
TAdapted Adapt(TAdaptee adaptee);
}
You could pass this adapter into a helper method for adapting multiple objects (assuming the adapt logic stays the same for multiple):
public IEnumerable<TAdapted> AdaptMultiple<TAdapted, TAdaptee>
(IEnumerable<TAdaptee> adaptees, IGenericAdapter<TAdapted, TAdaptee> adapter)
where TAdaptee : IAdaptee
where TAdapted : IAdapted
{
return adaptees.Select(adapter.Adapt);
}
For example, we can construct the following concrete classes:
public class ConcreteAdaptee : IAdaptee { }
public class ConcreteAdapted : IAdapted { }
public class ConcreteAdapter : IGenericAdapter<ConcreteAdapted, ConcreteAdaptee>
{
public ConcreteAdapted Adapt(ConcreteAdaptee adaptee)
{
// Adapt Logic
return new ConcreteAdapted();
}
}
And adapt them as such:
IGenericAdapter<ConcreteAdapted, ConcreteAdaptee> adapter = new ConcreteAdapter();
var adaptee = new ConcreteAdaptee();
var adapted = adapter.Adapt(adaptee);
var adaptees = new List<ConcreteAdaptee>();
var adapteds = AdaptMultiple(adaptees, adapter);
consider the following example :
interface IDog
{
void Bark();
}
interface ICat
{
void Meow();
}
class SomeDog : IDog
{
public void Bark()
{
Console.WriteLine(#"bark bark");
}
}
class SomeCat : ICat
{
public void Meow()
{
Console.WriteLine(#"meow meow");
}
}
class CatToDogAdapter : IDog
{
private ICat cat;
public CatToDogAdapter(ICat cat)
{
this.cat = cat;
}
public void Bark()
{
cat.Meow();
}
}
new Dog().Bark(); // bark bark
new CatToDogAdapter().Bark();// meow meow
this is how adapter works.
Let say you have a model MyAdaptedData and you recive data containing HotelName, Name,PropertyName from agoda , booking and tripadviser
for each booking model you need to write adapter
AgodaAdapter : MyAdaptedData{
public AgodaAdapter(AgodaModel agodaModel){
....
}
public stirng HotelName{
get{
return agodaModel.HotelNamebyAgoda;
}
}
....
}
Same for booking and tripadvisor.
Adapter pattern helps you to retrieve necessary data from external models.
Then you need to create specific adapter depending on the adaptee type. Use Factory method pattern
MyAdaptedData AdaptersFactory(object adaptee){
if(adaptee is AgodaModel)
return new AgodaAdapter(adaptee);
....
if(adaptee is XBookingModel)
return new XBookingAdapter(adaptee);
}
I've been trying to do something which I hoped would be simple, but turned otherwise.
I have a base class:
public class EntityBase
{
}
and two classes that inherit from it:
public class EntityA : EntityBase
{
}
public class EntityB : EntityBase
{
}
I want to use a container type that will wrap
An instance of EntityBase
A number of children which are other instances of the container type.
I want this container expose the exact type of the EntityBase instance it contains, so I use C# generics. But I could not manage to convince C# compiler to define a list of the container type (which has a type parameter now):
public class EntityNode<T> where T : EntityBase
{
private T _node;
private List<EntityNode<EntityBase>> _children = new List<EntityNode<EntityBase>>();
public EntityNode(T pNode)
{
_node = pNode;
}
public void AddChild(EntityNode<T> pNode)
{
//_children.Add(pNode); //this is not going to work...
}
public T Root
{
get { return _node; }
set { _node = value; }
}
}
Is it possible to allow EntityNode to contain a list which in turn contains EntityNode<EntityA>, EntityNode<EntityB> and EntityNode<EntityBase> instances?
What about using List<EntityNode<T>> instead of List<EntityNode<EntityBase>>:
private List<EntityNode<T>> _children = new List<EntityNode<T>>();
I have this code and I want to keep it elegant.
I got stuck at this inheriting issue and I would have to mess up the code if I do.
Help me keep it elegant. I don't mind making changes anywhere up and down the hierarchy; feel free to change the core.
I have these abstract classes (I omitted unrelated implementation to keep the question content short).
public abstract class Entity : IComparable
{
protected int _ID;
public abstract int ID { get; }
}
public abstract class SortedEntities<T> : IEnumerable<T> where T : Entity
{
Dictionary<int,T> _Entities;
}
And, obviously, an example of inheritance is as follows:
public class Contact : Entity { }
public class Contacts : SortedEntities<Contact> { }
And I also have more than just Contact and Contacts that inherit from Entity and SortedEntities that all act in the same manner.
At some point in my app, I want to select entities based on and ID list.
A sample code of what I want is:
Contacts LoadedContacts = new Contacts(); // load and fill somewhere else
// !!!NOT IMPLEMENTED YET!!!
Contacts SelectedContacts = LoadedContacts.GetFromIDList("1,4,7");
Where it returns a new Contacts object filled with those Contact objects of the ID's provided.
So, to allow that code for all classes inheriting from SortedEntities, I thought of adding this imaginative code to the abstract:
public abstract class SortedEntities<T> : IEnumerable<T> where T : Entity
{
// !!!NOT REAL CODE YET!!!
public abstract this<T> GetFromIDList(string IDCSV)
{
List<string> idlist = IDCSV.Split(',').ToList<string>();
return this.Where(entity => idlist.Contains(entity.ID.ToString()));
}
}
But obviously the this<T> is not allowed.
What I'm trying to tell the compiler is to make the return type of this method that of the inheriting class down the hierarchy.
That way, if someone calls LoadedContacts.GetFromIDList("1,4,7") it will return Contacts without having to cast it from SortedEntities<T> if I make it the return type, which would also require me to override the method in each inheriting class to hide the abstract method.
Am I forgetting something I already know?
Or is this completely not possible and I have to override and hide the method down the hierarchy for all inheriting classes?
A common solution is to add another generic type parameter that refers to the "current" type (like this refers to the "current" object):
public abstract class Entity : IComparable
{
protected int _ID;
public abstract int ID { get; }
}
public abstract class SortedEntities<TEntities, TEntity> : IEnumerable<TEntity>
where TEntities : SortedEntities<TEntities, TEntity>, new()
where TEntity : Entity
{
Dictionary<int, TEntity> _Entities;
public TEntities GetFromIDList(string IDCSV)
{
List<string> ids = IDCSV.Split(',').ToList<string>();
return new TEntities
{
_Entities = this.Where(entity => ids.Contains(entity.ID.ToString()))
.ToDictionary(e => e.ID)
};
}
}
Usage:
public class Contact : Entity
{
}
public class Contacts : SortedEntities<Contacts, Contact>
{
}
Note how the TEntities is restricted to a SortedEntities<TEntities, TEntity>. This does not really mean that TEntities can only refer to the current class, but as long as you follow the pattern of letting class X inherit from SortedEntities<X, Y>, it should work.
The new() constraint is required so you can instantiate a new instance of the "current" class.
Eric Lippert has indicated somewhere else that he dislikes this pattern. Act at your own risk!
it seems if i use an custom class as base of an entity,the ObjectContext.CreateObjectSet will fail with stackoverflow exception
code is:
// This is generated by EF4 and i modify it to my custom class
public partial class EntityA : GClass<EntityA>
{
......
}
public partial class TestEntities : ObjectContext
{
public ObjectSet<EntityA> EntityAs
{
get
{
if ((_EntityAs == null))
{
// here will throw stackoverflow exception
_EntityAs = base.CreateObjectSet<EntityA>("EntityAs");
}
return _EntityAs;
}
}
private ObjectSet<EntityA> _EntityAs;
}
// This is custom class
public partial class EntityA
{
}
// This is my custom base class
public class GClass<T> : EntityObject where T : class
{
public virtual string GetStr()
{
return "GClass";
}
}
I recommend creating an interface for your entity objects instead of changing the base class. Generated code should not be modified.
Update: Due to unexplained downvotes, I'm adding the code below, which spells out precisely what I mean:
// Generated by EF4
public partial class EntityA : EntityObject
{
...
}
// Interface defined in another file
public interface IGClass<T> where T : IGClass<T>
{
string GetStr();
}
// Automatically generated by T4 template
public partial class EntityA : IGClass<EntityA>
{
public virtual string GetStr()
{
return "GClass";
}
}
The resulting code does use CRGP, but does so via an interface instead of a base class.
More info on T4 templates is here.
I am trying to use StructureMap to register some types that implement a generic interface and are instantiated via a factory.
My code:
public interface IManagerBase<T, TKey> : IDisposable
{
// Get Methods
T GetById(TKey Id);
}
public partial interface IServerHostManager : IManagerBase<ServerHost, int>
{
// ServerHost Specific Get Methods
}
partial class ServerHostManager : ManagerBase<ServerHost, int>, IServerHostManager
{
// Implementation
}
public class ManagerFactory : IManagerFactory
{
public IServerHostManager GetServerHostManager()
{
return new ServerHostManager();
}
}
This works fine:
For<IServerHostManager>().HybridHttpOrThreadLocalScoped()
.Use(new ManagerFactory().GetServerHostManager());
My factory is called and a new instance of IServerHostManager is returned.
Is there any way I can scan for all generic types and have them instantiated via my factory?
This does not work due to ServerHostManager being an internal class:
Scan(x =>
{
x.AssemblyContainingType(typeof(IManagerBase<,>));
x.AddAllTypesOf(typeof(IManagerBase<,>));
x.ConnectImplementationsToTypesClosing(typeof(IManagerBase<,>))
.OnAddedPluginTypes(t => t.HybridHttpOrThreadLocalScoped());
});
What scan command can I use to tell SM to call my factory?
Thank you,
Rick
Followup added on 5/4:
Sorry for the delay in following up.
I’ve got a bunch of manager objects (> 75) that CodeSmith’s nHibernate template has created. They are normally accessed via a factory object. Instead, I’d like to scan for them have them all registered automatically.
This is how I register the objects now:
For<IActivityLogManager>().HybridHttpOrThreadLocalScoped()
.Use(new ManagerFactory().GetActivityLogManager());
For<IAspnetUserManager>().HybridHttpOrThreadLocalScoped()
.Use(new ManagerFactory().GetAspnetUserManager());
Here are the objects
public interface IManagerBase<T, TKey> : IDisposable
{
// Get Methods
T GetById(TKey Id);
}
public partial interface IActivityLogManager : IManagerBase<BusinessObjects.ActivityLog, int>
{
// Get Methods
IList<ActivityLog> GetByActivityTypeId(System.Int32 activityType);
}
public partial class ActivityLogManager : ManagerBase<BusinessObjects.ActivityLog, int>, IActivityLogManager
{
public IList<ActivityLog> GetByActivityTypeId(System.Int32 activityType)
{
// Code to fetch objects
}
}
public partial interface IAspnetUserManager : IManagerBase<BusinessObjects.AspnetUser, System.Guid>
{
// Get Methods
IList<ActivityLog> GetByActivityTypeId(System.Int32 activityType);
}
public partial class AspnetUserManager : ManagerBase<BusinessObjects.AspnetUser, System.Guid>, IAspnetUserManager
{
public IList<AspnetUser> GetAll()
{
// Code to fetch objects
}
}
My Scan code:
Scan(x =>
{
x.AssemblyContainingType(typeof(IManagerBase<,>));
x.AddAllTypesOf(typeof(IManagerBase<,>));
x.ConnectImplementationsToTypesClosing(typeof(IManagerBase<,>))
.OnAddedPluginTypes(t => t.HybridHttpOrThreadLocalScoped());
});
The Scan code above does not find any objects in the assembly.
I hope this clarifies my scenario.
Thank you,
Rick
This issue can be solved by making the assembly a friend:
[assembly: InternalsVisibleTo("AssemblyB")]
http://msdn.microsoft.com/en-us/library/0tke9fxk.aspx