I'm trying to use Automapper to flatten a Entityframework object that has a nested complex property to a few various models that all inherit the same common properties from a base class, a simplified version of this is as follows:
public class EFObject {
public int Id { get; set; }
public int NestedId { get; set; }
public virtual AnotherModel AnotherModel { get; set; }
}
public class AModel : Model {
public int AModelId { get; set; }
}
public class BModel : Model {
public int BModelId { get; set; }
}
As both AModel and BModel share a common base (Model) ideally I would like to declare a common map like so:
mapper.Map<AnotherModel, Model>();
And then when mapping EFObject to AModel I would map the AModelId property within
mapper.Map<EFObject, AModel>();
and then include the AnotherModel -> Model map so that I wouldn't have to map the common properties multiple times (once for AModel and again for BModel, etc).
I was able to achieve the above by using an AfterMap, i.e.
CreateMap<EFObject, AModel>()
.AfterMap((src, dest) => Mapper.Map(src.AnotherModel, dest))
.ReverseMap();
However there is a fairly major issue with this solution in that it relies on the static instance of Automapper, and as I am dependency injecting an instance of Automapper, my unit tests that use this map are all failing due to the static Mapper not being instantiated.
I could get around this problem by initializing the static instance in my unit test, but as it requires knowledge of how your maps are structured, it defeats the aim of using Automapper (I feel).
I also know that I could write a converter for each Model, however that isn't ideal as it produces a lot of additional code for something I feel is supported but I'm struggling to find the answer for.
Any ideas on the best way to structure my maps to get around this problem?
Related
Hello I'm writing a little C# web app using asp.net core 1.1 MVC with EF (code first)
I want to know what is the best engineering choice.
Let's assume that I have a class and I need to calculate something using one or more related properties; let's make an example:
class A
{
public virtual int Id { get; set; }
public virtual Collection<B> Bs { get; set; }
public int GetMaxB()
{
return Bs.Max( b => b.Num ); /*simple example, can be more complex */
}
}
class B
{
public virtual int Id { get; set; }
public virtual int Num { get; set; }
}
So, for GetMaxB() (let's think about a more complex function, not only one line) what is the best option?
a function in the model class
a generated (NotMapped) property in the model class
a function in controller
other
Your logic can be a part of VM, you may not want to have it mix with the Model, which should be a pure class with properties.
Depends upon situations and nature of property.
A calculated property like DiscountValue (which depend few other properties) be part of Model class.
If use of a GetMaxB() is less frequent then it can be a function in Model.
If GetMaxB() is only reason for which collection class is used in Class A, then you can think separate out provided use is not frequent.
I've been getting my head into WPF the last few days, coming from a WinForms background, I just love the flexibility, especially in terms of binding.
However, I had a question after reading the following article on MVVM: http://blog.alner.net/archive/2010/02/09/mvvm-to-wrap-or-not-to-wrap.aspx
How to go about Models I have no control over, I cannot add interfaces to it, etcetera, I can only use them as-is?
Looking at the article, one option for me is to just directly expose the Model in my ViewModel, but would this be a good way to go about it? I could also use the wrapping option, but how do I bubble changes to those bubbles back to the ViewModel if they don't have a INotifyPropertyChanged interface? Are there any other options that allow TwoWay-binding to these Models?
EDIT:
Consider the following classes as models I cannot modify, what are my options:
[DataContract]
public class NPCTypeData
{
[DataMember]
public string Name;
[DataMember]
public List<NameAlias> Emotions;
}
[DataContract]
public class NameAlias
{
[DataMember]
public string Name;
[DataMember]
public string Alias;
}
I don't really care about the code required to turn these into bindable classes, I just want one or more examples on where to start with nested dependencies like this.
Do I copy all data to a Model that does have bindable properties and just leave these for serialization, do I wrap them, or what?
I agree with Henk, and would add that one option can be the "dynamic proxy class creation" which is what entity framework does. Basically: you have your POCO objects, and Entity framework can attach dynamically the necessary functionality to track the changes on model.
There's also an option to inherit from a class, and decorate the class with AOP attribute which generates all the necessary plumbing on the fly.
You can google for:
AOP INotifyPropertyChanged - http://www.postsharp.net/
Automatic INotifyPropertyChanged using Dynamic Proxy - http://jonas.follesoe.no/2009/12/23/automatic-inotifypropertychanged-using-dynamic-proxy/
When I had such problem, I basically used Henk solution, creating new classes and wrapping each property, using AutoMapper. Did it work & was it maintable? Yes, it worked, and it was maintable. Was it painful? Yes.
public class NPCTypeDataViewModel
{
public string Name {
get;
set;
}
public List<NameAliasViewModel> Emotions {
get;
set;
}
public NPCTypeDataViewModel(NPCTypeData data){
Name = data.Name;
Emotions = data.Emotions.Select(x => new NameAliasViewModel(x))
.ToList();
}
public NPCTypeData GetModel(){
var ntd = new NPCTypeData(){
Name = Name,
Emotions = Emotions.Select(emo => emo.GetModel())
.ToList()
};
return ntd;
}
}
public class NameAliasViewModel
{
public string Name {
get;
set;
}
public string Alias {
get;
set;
}
public NameAliasViewModel(NameAlias alias){
Name = alias.Name;
Alias = alias.Alias;
}
public NameAlias GetModel(){
return new NameAlias(){
Name = Name,
Alias = Alias
};
}
}
I'm trying to perform a mapping between an EF domain object to a DTO object using the Automapper 'Project' method, but am having problems when trying to project from an interface to a concrete class. My EF domain object implements an interface that I use commonly with my lookup tables:
public interface ILookupItem
{
int Id { get; set; }
string Name { get; set; }
}
and here's an example of my domain object:
public partial class ReportType : ILookupItem
{
public int Id { get; set; }
public string Name { get; set; }
}
In my app, I'm using a DTO object which exactly matches the domain object interface:
public class LookupItemModel
{
public static void CreateMapping(IConfiguration configuration)
{
configuration.CreateMap<ILookupItem, LookupItemModel>();
}
public int Id { get; set; }
public string Name { get; set; }
}
I then perform my database query with a call such as:
return DbContext.Query<ReportType>().Project().To<LookupItemModel>();
however on this call Automapper gives an error about missing a required mapping to perform the function:
Missing map from ReportType to LookupItemModel. Create using Mapper.CreateMap<ReportType, LookupItemModel>.
I would have assumed that the mapping could be performed from the interface since all it should need to know are the properties which to pull data for (Id & Name). Am I missing something to be able to perform this projection without creating maps for each concrete implementation of my interface?
Thanks!
I asked in a comment but haven't had a response yet but I'm fairly sure this is your problem so I'm going to go ahead and make it an answer.
You're creating the mapping between ILookupItem and LookupItemModel but you aren't ever calling the method that creates the map - LookupItemModel.CreateMapping().
Before you do the mapping you need to call this method:
LookupItemModel.CreateMapping(your IConfiguration);
return DbContext.Query<ReportType>().Project().To<LookupItemModel>();
That said, instead of setting up your mapping logic inside your models, I would create an AutoMapper configuration class that sets up all your maps. Something like:
public class AutoMapperConfig {
public static CreateMaps() {
CreateLookupItemMaps();
}
public static CreateLookupItemMaps() {
Mapper.CreateMap<ILookupItem, LookupItemModel>();
}
}
Or a cleaner approach would be to use AutoMapper Profiles
And then call AutomapperConfig.CreateMaps() during your app startup and you should be good.
In my domain model I have an Entity object that looks as follows:
public class Group
{
public int idGroup { get; set; }
public string Description { get; set; }
}
I have a repository for this object:
public class GroupRepository : IGroupRepository
{
public Group LoadGroup(int idGroup)
{
//imitation of SQL data reader
Group g = new Group();
g.idGroup = Convert.ToInt32(r["idTipoGrupo"]);
g.Description = Convert.ToString(r["Descricao"]);
return g;
}
}
But now I need to get some extra information from data store about Group objects through a new function in my created repository, here are the fields I need:
public bool HasChildGroups { get; set; }
public int ChildGroupsCount { get; set; }
public bool HasDeals { get; set; }
public int DealsCount { get; set; }
These properties look to me like a "service" or "helper" properties and I don't plan to use them everywhere in my application, only few times, but I need them. The simplest thing I could think of is that I added these "service" properties to my Group object and created a method in my repository that populates them. But I consider doing this wrong, as it is the Entity and I don't need them in here. So where should I keep such "service" objects? Do I have to create a new class that inherits from Group like this:
public class GroupHelper : Group
{
public bool HasChildGroups { get; set; }
public int ChildGroupsCount { get; set; }
public bool HasDeals { get; set; }
public int DealsCount { get; set; }
}
Or should I consider using some Data Transfer Objects?
How would you solve this problem?
Any help appreciated.
The first question to ask is how the state of the proposed GroupHelper object is managed. Attributes such as HasChildGroups seems like they would be altered as a result of behaviors invoked on a Group entity. If so, then they should be first class entities in your domain model, perhaps event part of the group entity itself. If the properties are managed outside of your domain model then you can just query that data as you would any other external data source. I would have this be a standalone object, perhaps called something like GroupInfo not extending Group itself.
What seems to be the issue here is that you have query requirements that aren't in alignment with the shape of your entities. In that case you have the flexibility to decouple your read-models from your domain models. Read-models are intended to fulfill query requirements and your domain models are intended to host behavior associated with your domain.
HasChildGroups [...] look to me like a "service" or "helper" properties [...] But I consider doing this wrong, as it is the Entity and I don't need them in here.
If you concider your Group object to be a data access object and you have a separate model for, say, viewdata, you're right.
But this may also be a fat class, providing in view-specific and database-specific code. It's not plain wrong.
You could indeed create a GroupDTO class that provides the properties you require in the application but not for the data access, to separate concerns.
Lets say I have two classes:
public class A
{
public virtual int Id { get; set; }
public virtual Object1 Obj { get; set; }
}
public class B : A
{
public new virtual Object2 Obj { get; set; }
}
I use Fluent NHibernate and I have created two different mappings for the two classes. However, when I try to query class A in my repository, FNH finds both class B and A, which kind of makes sense since both are A.
Example (this criteria will query over both A and B):
public List<T> GetByName(string name)
{
return Session.CreateCriteriaOf<A>.Add(Restrictions...);
}
When writing CreateCriteriaOf<A>, I only want to query over A - not B. How can I solve my problem?
I think you better make an inheritance tree where both A and B derive from a common (abstract) base type. Then NHibernate can make the distinction by a discriminator column.
Of course, your data model should accommodate this, so I hope your model is not prescribed in any way.