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.
Related
I am using MVVM and it is working all fine, except one thing, accessing parent model objects.
The goal is to access any model object's parent object directly, but I could not find a propper way to do that.
For example:
Grandparents
--- Parents
--- --- Children
--- --- --- Grandchildren
I have a reference to a Child, but I have to check some properties of Children and maybe Parents.
Currently the code is running through all higher level objects until there is a successful match in the Parent's Children's Grandchildren with my Grandchild object, and then it is possible to check the properties.
But this is kind of disgusting in terms of smart code and efficiency, independent of how this is done, I do not want to run through all my data for a lucky match. This is the current imoplementation, some other parts are done by using LINQ.
var someChild = calledChild;
foreach (Grandparent gParent in mainViewModel.SelectedEnvironment.GrandParents)
{
foreach (Parent parent in gParent.Parents)
{
foreach (Child child in parent.Children)
{
if (child.A == calledChild.A)
{
// Match
System.Diagnostics.Debug.WriteLine("CalledChilds grandparent is " + gParent.Name);
}
}
}
}
The model is set up in classes with definitions like this:
public class Parent : ObservableObject
{
public const string NamePropertyName = "Name";
private string _name;
public string Name
{
get
{
return _name;
}
set
{
if (_name == value)
{
return;
}
_name = value;
RaisePropertyChanged(NamePropertyName);
}
}
public const string ChildrenPropertyName = "Children";
private ObservableCollection<Child> _children;
public ObservableCollection<Child> Children
{
get
{
return _children;
}
set
{
if (_children == value)
{
return;
}
_children = value;
RaisePropertyChanged(ChildrenPropertyName);
}
}
}
The model is saved in a json file and parsed back to the model's root object type for usage.
I can not just add a new reference "Parent" to the "Child" object, because it would end up in a loop, due to this concepts restrictions.
It would be great to get references instead of copies of the whole model branch.
Is there a way to access the parent objects directly?
Thank you all!
Easiest way is to store direct reference to parent node in child nodes:
public class ParentNode
{
private ObservableCollection<ChildNode> _children;
public ParentNode()
{
_children = new ObservableCollection<ChildNode>();
Children = new ReadOnlyObservableCollection<ChildNode>(_children);
}
public ReadOnlyObservableCollection<ChildNode> Children { get; }
public void AddChild(ChildNode item)
{
if (item.Parent != null) throw new InvalidOperationException("Item is already added to another node");
item.Parent = this;
_children.Add(item);
}
public void RemoveChild(ChildNode item)
{
if (item.Parent != this) throw new InvalidOperationException("Item is not direct child of this node");
item.Parent = null;
_children.Remove(item);
}
}
public class ChildNode
{
public ParentNode Parent { get; internal set; }
}
just be careful, because this introduces circular references - parent references children and vice versa. It is kind of violation of DRY principle, because the shape of the tree is defined twice and you could easily get out of sync (e.g. you set ChildNode.Parent property to something else than the actual parent).
There are ways to workaround it, but I think you could start with this.
I have web api controller like this:
public class ParentController : ApiController
{
[HttpGet]
public IHttpActionResult GetParent()
{
//instatiating child class
var child = new Child
{
ChildProp1 = "childValue1",
ChildProp2 = "childValue2",
ParentProp1 = "parentValue1",
ParentProp2 = "parentValue2"
};
//up casting is implicit
Parent parent = child;
//returning parent as Json http request
return Ok(parent);
}
private class Child : Parent
{
public string ChildProp1 { get; set; }
public string ChildProp2 { get; set; }
}
private class Parent
{
public string ParentProp1 { get; set; }
public string ParentProp2 { get; set; }
}
}
and it works perfectly except it return Json result of both parent and child properties and What I need is only properties of parent class
Output response body:
{
"childProp1": "childValue1",
"childProp2": "childValue2",
"parentProp1": "parentValue1",
"parentProp2": "parentValue2"
}
Thanks!
You could return an anonymous type
return Ok(new { ParentProp1 = parent.ParentProp1, ParentProp2 = parent.ParentProp2 });
You could add the JsonIgnore attribute to the Child properties (though this would mean that you wont be able to return them as JSON in other pieces of code.)
[JsonIgnore]
public string ChildProp1 { get; set; }
[JsonIgnore]
public string ChildProp2 { get; set; }
You could create an interface IParent with only the parent properties ParentProp1 and ParentProp2 and then use a custom contract resolver (as seen in this question) with JsonSerializerSettings.ContractResolver to tell it to serialize only the interface properties.
return Json(parent, new JsonSerializerSettings {
ContractResolver = new InterfaceContractResolver (typeof(IParent))
});
Option #3 is probably the best because unlike Option #1 you would only have to redefine your properties in the interface instead of possibly in multiple HttpGet methods that return anonymous types. Also, unlike Option #2, you wouldn't be restricted from returning your child properties as JSON from other HttpGet methods.
Although you are casting it, the instance is still actually a Child so when the JSON serializer does parent.GetType() it ends up with Child and gets the properties of Child.
If you want the result to just be the properties of Parent then you need to just create an instance of Parent to start with.
So, I have a list of children on my parent object, and I want to persist them on my SQL Server. When I run the application for the first time, all the children get their FK correctly, but when I run it again and no new parent is added, the new child(of an existing parent) doesn't get it's parent FK, just NULL. How can I map the parent FK on my child mapping for those situations?
I've tried the Inverse() method, but as I need the parent key to be generated all children gets null anyway. I need something like, if the parent is new, then the parent will update it's children FK, but when only the child is new I would need it to do the Inverse() method, is it possible?
Some more info:
Every time I call the ParentPersist method, and it cascades as needed. I've added the AddChild() method to set the ParentId when a new child is added to the list, it's working as I debugged it, so the child is setting it's ParentId correctly.
The objects are like the following:
public class Parent
{
public virtual int Id { get; set; }
...
public virtual IList<Child> Children{ get; set; }
public virtual void AddChild(Child ch)
{
ch.IdParent = this.Id;
Children.Add(ch);
}
}
public class Child
{
public virtual int Id { get; set; }
...
public virtual int IdParent {get;set;}
}
And my mapping:
public class ParentMapping : ClassMap<Parent>
{
public ParentMapping ()
{
Id(cso => cso.Id).GeneratedBy.Identity();
...
HasMany(cso => cso.Children).KeyColumn("IdParent").Cascade.SaveUpdate().Not.LazyLoad();
}
}
public class ChildMapping : ClassMap<Child>
{
public ChildMapping ()
{
Id(cso => cso.Id).GeneratedBy.Identity();
...
}
}
Your logic (e.g. Add() method in Parent, Inverse() mapping) was OK. You were almost there. There is only one BUT...
In general, the proper (if not only correct) solution is to use objects to express realtion and not just the ValueType/int values. That's why we call it ORM - Object-relational mapping
Object in C# should look like this:
public class Parent
{
...
// correct mapping of the children
public virtual IList<Child> Children{ get; set; }
// this method uses the below updated Child version
public virtual void AddChild(Child ch)
{
// this is replaced
// ch.IdParent = this.Id;
// with this essential assignment
ch.Parent = this;
Children.Add(ch);
}
}
public class Child
{
...
// instead of this
// public virtual int IdParent {get;set;}
// we need the reference expressed as object
public virtual Parent Parent { get; set; }
}
So, now, once we have objects in place, we can adjust the mapping like this:
// parent
public ParentMapping ()
{
...
HasMany(cso => cso.Children)
.KeyColumn("IdParent")
.Inverse() // this is essential for optimized SQL Statements
.Cascade.SaveUpdate() // All delete orphan would be better
.Not.LazyLoad();
}
...
// Child
public ChildMapping ()
{
...
References(x => x.Parent, "IdParent"); // it is a to use Inverse()
}
With this Business Domain Model and the mapping (Inverse(), assigning bothe relation ends in Add() method...), NHibernat will have enough information to always (insert, update) issue proper SQL statements
NOTE: One could ask why to map Parent Parent { get; set; } and not just the int IdParent { get; set; }... In fact, if we would have existing Parent (with NOT transient ID, i.e. > 0) - there won't be any difference. The trick/problems would appear on a new Parent insertion. Almost always, assignement of the children comes before the Parent is persiseted (flushed), and its ID is recieved from DB (sql server identity). And that could/would cause the child.IdParent == 0 ...
We should remember, that in general - ORM is about objects, i.e. relation is represented by Reference types.
I have two entities:
public class Parent
{
public virtual int Id { get; set; }
}
public class Child
{
public virtual int Id { get; set; }
public virtual int ParentId
{
get
{
if (Parent != null)
return Parent.Id;
return -1;
}
set
{
if (Parent != null)
Parent = new Parent();
Parent.Id = value;
}
}
protected virtual Parent Parent
{
get;
set;
}
}
The Parent property is set up like this to simplify the API side, and I do not want to change it to expose this property publicly. I have an override of the mappings for the Child class to accommodate this:
public class ChildMappingOverrides : IAutoMappingOverride<Child>
{
public void Override(AutoMapping<Child> mapping)
{
mapping.References<Parent>(Reveal.Member<Child>("Parent")).Column("Parent_id");
mapping.IgnoreProperty(x => x.ParentId);
}
}
Now, if I want to query all the Child objects for a given parent Id, I would perform this:
session.QueryOver<Child>().Where(c => c.ParentId == 1);
However, this throws a QueryException:
could not resolve property: ParentId of: My.Namespace.Child
How can I retrieve the set of Child objects that have a particular Parent Id?
Untested, but you could try this:
session.QueryOver<Child>()
.Where(Restrictions.Eq(
Projections.SqlProjection(
"{alias}.Parent_id as ParentId",
new[] { "ParentId" },
new[] { NHibernateUtil.Int32 }), 1))
.List<Child>();
You're not going to be able to query on unmapped associations in any NHibernate query, but this at least minimizes the loss of compile-time checking.
This is somewhat limited from what I can tell. {alias} will always be replaced by the alias of the root entity, meaning if you want to do this for a more complex query that doesn't start with Child, you might be out of luck.
I've solved it by using CreateSQLQuery instead of QueryOver:
session.CreateSQLQuery("SELECT C.* FROM CHILD C WHERE C.Parent_id = (:id)")
.AddEntity(typeof(Child))
.SetInt32("id", parentId)
.List<Child>();
I'd like to see a better way if possible, losing the compile-time checking is kind of a downer.
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;
}
}