This question already has answers here:
How to assign parent reference to a property in a child with AutoMapper
(2 answers)
Closed 10 years ago.
So have have an model object TreeNode:
Public Class TreeNode{
Public int NodeId {get;set;}
Public String Name {get;set;}
Public int ParentId {get;set;}
Public TreeNode Parent {get;set;}
Public List<TreeNode> Children {get;set;}
}
This structure is powered by a databases using an Adjacency List Pattern. I'm using a WCF service with AutoMapper to populate my Model classes.
I want to do something like this:
public static void ConfigureMappings()
{
Mapper.CreateMap<TreeNodeDto, Taxonomy>()
.AfterMap((s, d) =>
{
//WCF service calls to get parent and children
d.Children = Mapper.Map<TreeNodeDto[], TreeNode[]>(client.GetTreeChildren(s)).ToList();
d.Parent = Mapper.Map<TreeNodeDto, TreeNode>(client.GetTreeParent(s));
});
}
But obviously this causes an infinite loop (it does work if I only map children tho). Is there any way to populate my tree structure using AutoMapper?
I found this partial solution. At first I though it was what I was looking for but after further inspection it only works if you start at the top of the tree. It doesn't populate the Parent nodes if you start in the middle.
How to assign parent reference to a property in a child with AutoMapper
public static void ConfigureMappings()
{
Mapper.CreateMap<TreeNodeDto, Taxonomy>()
.AfterMap((s, d) =>
{
//WCF service calls to get parent and children
d.Children = Mapper.Map<TreeNodeDto[], TreeNode[]>(client.GetTreeChildren(s)).ToList();
foreach( var child in d.Children)
{
child.Parent = d;
}
}
Related
This question already has answers here:
Linq list of lists to single list
(4 answers)
Closed 2 years ago.
I have an EF DB context query that produces a list of objects that look like this:
public interface Parent
{
public string Name { get; set; }
public virtual ICollection<Child> Children {get; set;}
}
public interface Child
{
public string Name {get; set;}
public boolean isValid {get; set;}
}
The query itself looks like
var list _dbContext.Parents.Include(x => x.Children).ToList();
I want to be able to query each parent, pull out the details of each child that has isValid = true and then store them all in a list, but I can't figure out the syntax.
I was trying to do something like
list.Where(x => x.Children.Where(child => child.isValid).toList()).toList();
But the above just produces an IList<IList>
I've accomplished that using an expression like this:
var list.Where(x => x.Children.Any(child => child.isValid)).toList();
Keyword Any is very powerful in this cases
I'm currently experiencing an issue when trying to map the entire destination object from a child property on the source object. Something similar as described here: Automapper - How to map from source child object to destination
I've made use of the .ConstructUsing method as described in the link above however I'm seeing some weird behaviour where the outputted, mapped object is getting values from the parent instead of the child.
I made a demo of the problem here: https://dotnetfiddle.net/OdaGUr
Is this a problem with my code, should I be using a different method to achieve what I'm trying to do or is this a fault with AutoMapper?
EDIT:
public static void Main()
{
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<Child1, Child2>();
cfg.CreateMap<Parent, Child2>().ConstructUsing((src, ctx) => ctx.Mapper.Map<Child2>(src.Child1));
});
var mapper = config.CreateMapper();
var parent = new Parent{
Id = 1,
Child1 = new Child1 {
Id = 2
}
};
var child2 = mapper.Map<Parent, Child2>(parent);
Console.WriteLine(child2.Id); // Returns 1. Expect this to be 2 from Parent.Child1
}
public class Parent
{
public int Id {get;set;}
public Child1 Child1 {get;set;}
}
public class Child1
{
public int Id {get;set;}
}
public class Child2
{
public int Id {get;set;}
}
ConstructUsing() is used to create the destination object, where the value should be stored in. In your case you are returning a Child2 object with the Id value set to 2 (as returned by the ctx.Mapper.Map<Child1, Child2>(src.Child1) line).
However, after the object has been created, the default mapping will still be applied. This means that the Parent.Id value will be saved in the Child2.Id property, because the names of the property match ("Id"). So, the initial value of 2 will be replaced with the value 1 from the Parent object.
Depending on what you want to do, you might want to use ForMember() to configure special handling on how the property values should be mapped. An example would be:
.ForMember(dest => dest.Id, src => src.MapFrom(it => it.Child1.Id))
This question already has answers here:
Include Grandchildren in EF Query
(2 answers)
Closed 7 years ago.
Model:
public class Parent
{
public int Id { get; set; }
public ICollection<Child> Children { get; set; }
}
public class Child
{
public int Id { get; set; }
public int IdGrandChild { get; set; }
public virtual Grandchild Grandchild { get; set; }
}
public class Grandchild
{
public int Id { get; set; }
}
I have an existing Parent entity with a Children collection. After some operations i want to load newly added children objects to Parent's collection from database like this
_context.Entry(parent).Collection(f => f.Children).Load();
But when i am doing this like that, the Grandchild object in every newly added collection element is null. I also tried to include grandchild in this way but still the Grandchild object is null.
_context.Entry(parent).Collection(f => f.Children).Query().Include(c => c.Grandchild).Load();
How to correctly load the new items to the Parent's Children collection including Grandchild objects?
EDIT:
I dont know why this question was marked as duplicate?
My problem is: I already have existing (loaded/tracked) parent entity in one context instance (form) and then in another context instance (form) I modified entity child's collection ( add or remove child). Finally I want to load these newly added entries to parent entity collection in first context instance using one of this previously written methods but after that the newly added object are loaded but their grandchild's are nulls.
I don't know how to correctly load these new child objects to existed (tracked) parent entity without getting a nulls.
I usually use the following(wihout load)
Parent parent = _context.Parent.Include(p => p.Children.Grandchild).FirstOrDefault();
and if my Grandchild was a collection, I would use
Parent parent = _context.Parent.Include(p => p.Children.Select(c => c.Grandchild).FirstOrDefault();
Ive searched for this for few days now and cant seem to get anything to work, I am using c# MVC Entity Framework with Automapper and im trying to achieve the below ViewModels (mainly LostDocumentVM) to be mapped from my database, all other properties will be set in controllers.
Here is my ViewModels...
DocumentVM
{
Public Enum.HistoricType HistoricType {get;set;}
Public DocumentChildVM Document { get; set;}
}
DocumentChildVM
{
Public bool ShowHistoricLink {get;set;}
Public IEnumerable<ListDocumentVM> DocumentsToReview {get;set;}
}
ListDocumentVM
{
Public int Id {get;set;}
Public string Name {get; set;}
Public DateTime? ReviewDate {get;set;}
}
I initialise the DocumentVM like this...
DocumentVM documentVM = DataContext.SystemUser.Where(x=>x.SustemUserID==LoggedOnUserID).Project().To<DocumentVM>().SingleOrDefault();
And my mapping is like this...
Mapper.CreateMap<SystemUser,DocumentVM>()
.ForMember(dest=>dest.Document.DocumentsToReview, opt=>opt.MapFrom(src=>src.Documents.Where(x=>x.DocumentType == Enum.DocumentType.Assessment));
Im new to AutoMapper and struggling to get more advanced mappings to work.
Yes, your ForMember member must refer to a member on the destination type, and yours is referring to a member on the child type. Instead, you'll need to create an AfterMap function that fills in this information on that child entity.
It's not difficult, but you have a bit of a strange set up where a child object Document has a property DocumentsToReview from another property on the parent DocumentVM:
documentVM.Document.DocumentsToReview =
src.Documents.Where(doc => doc.DocumentType == Enum.DocumentType.Assessment);
When you have to shuffle data between sibling/nephew members, it gets a little more challenging.
To do this with AfterMap:
Mapper.CreateMap<SystemUser, DocumentVM>()
.AfterMap((src, dest) => dest.Document.DocumentsToReview =
src.Documents.Where(doc => doc.DocumentType == Enum.DocumentType.Assessment));
I'm having a bit of an issue. I don't quite know how to handle the situation so I'll just explain a simplified scenario and hopefully you can help me.
I'm trying to map a parent database object to a parent bll object. In this parent database object, there is a foreign key to the ID of the child, and in my parent bll object I use the child bll object (containing more than just an ID).
So here are my bll objects:
public class Parent
{
public int ID { get; set; }
public Child Child { get; set; }
}
public class Child
{
public int ID { get; set; }
public string FirstName { get; set; }
}
And here is my mapper class/method:
public class ParentMapper
{
public Parent MapFromSource(ParentDatabaseObject parentDO)
{
Parent parent = new Parent();
parent.ID = parentDO.ID;
parent.Child = ???;
return parent;
}
}
I don't think it's very important what the ParentDatabaseObject looks like in this case, I'd just like to know how I should map the parent.Child object.
I have considered the following:
parent.Child = new Child();
parent.Child.ID = doParent.Child.Id;
parent.Child.FirstName = doParent.Child.FirstName;
Which doesn't feel right, 'cause I kind of have the urge to put this in my ChildMapper, which leads me to my second way of implementing this (assuming I have a seperate child mapper and have an instance of it called childMapper):
parent.Child = childMapper.MapFromSource(parentDO.Child);
But I kind of have the feeling that using this way of mapping is making my code a bit tightly coupled, because I'd be using my ChildMapper in my ParentMapper.
So I guess my question is: how should I implement this kind of mapping. Is this last method correct or is there something even better? I'm already discarding the first thing I tried.
Thanks for your help!
(I did research before posting this question and this was the closest I could find:
Data Mapper for Child Objects , but I wasn't really content with the only answer in there)
Shouldn't it be better -
parent.Child = childMapper.MapFromSource(parentDO.FoeignKeyToTheChild);
I think you should have methods to get object by Id.
EDIT : If your mapper doesn't DataAccess code, then you have to map the child within your Repository. As your Repository already have DataObjects ready, you can do it the following way -
ParentMapper:
public class ParentMapper
{
public Parent MapFromSource(ParentDo parentDo)
{
Parent parent = new Parent();
parent.Id = parentDo.Id;
return parent;
}
}
ChildMapper:
public class ChildMapper
{
public Child MapFromSource(ChildDo childDo)
{
Child child = new Child();
child.Id = childDo.Id;
child.FirstName = childDo.FirstName;
return child;
}
}
Repository:
public class Repository
{
//you already have parentDo
//you already have childDo
public Parent GetParent()
{
Parent parent = parentMapper.MapFromSource(parentDo);
parent.Child = childMapper.MapFromSource(childDo);
return parent;
}
public Child GetChild()
{
Child child = childMapper.MapFromSource(childDo);
return child;
}
}
Otherwise, your Mapper must have access to DataAccess code.