{"id":1069,"date":"2010-03-15T22:37:43","date_gmt":"2010-03-15T21:37:43","guid":{"rendered":"http:\/\/www.gamlor.info\/wordpress\/?p=1069"},"modified":"2021-03-11T09:45:22","modified_gmt":"2021-03-11T08:45:22","slug":"managing-1n-and-nn-object-relations","status":"publish","type":"post","link":"https:\/\/www.gamlor.info\/wordpress\/2010\/03\/managing-1n-and-nn-object-relations\/","title":{"rendered":"Managing 1:N and N:N Object Relations"},"content":{"rendered":"<p><a href=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2010\/03\/objects-relation1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-1078 alignright\" title=\"objects-relation\" src=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2010\/03\/objects-relation1-124x300.png\" alt=\"object relations\" width=\"124\" height=\"300\" \/><\/a>When you design a domain model you normally have lots of 1:n and n:n relations. Many developers are quite familiar how to translate such relations into a <a href=\"http:\/\/en.wikipedia.org\/wiki\/Relational_model\">relational model<\/a>. But how do you translate such relations into an object-model? There\u2019s no hard guideline for that. In this post I explain what I usually do.<\/p>\n<h3>The Domain Model<\/h3>\n<p>For the examples I use a this small domain-model. Our application has authors, which write posts. An author has multiple posts and a post has only one author. Each post can have multiple tags and a tag is used for multiple posts.<\/p>\n<h3>The Possibilities<\/h3>\n<p>The majority of object oriented language give two tools for this job, references and collections. And therefore a lot of possibilities.<\/p>\n<ol>\n<li>Referencing from the \u2018child\u2019. In our example the post would have a reference to the author.<\/li>\n<li>Referencing from the \u2018parent\u2019. In our example the author would have a collection of all its posts.<\/li>\n<li>Bidirectional reference, in our example the post has a reference to the author and the author a collection of his posts.<\/li>\n<\/ol>\n<p>And in the n:n scenario all this possibilities above also apply. Just that each participant uses collections.<\/p>\n<p><a href=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2010\/03\/reference-on-child.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-1079\" title=\"reference-on-child\" src=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2010\/03\/reference-on-child-300x208.png\" alt=\"\" width=\"300\" height=\"208\" srcset=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2010\/03\/reference-on-child-300x208.png 300w, https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2010\/03\/reference-on-child.png 500w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><a href=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2010\/03\/collection-on-parent.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-1080\" title=\"collection-on-parent\" src=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2010\/03\/collection-on-parent-245x300.png\" alt=\"\" width=\"245\" height=\"300\" srcset=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2010\/03\/collection-on-parent-245x300.png 245w, https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2010\/03\/collection-on-parent.png 500w\" sizes=\"(max-width: 245px) 100vw, 245px\" \/><\/a><a href=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2010\/03\/bidirectional-references.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-1083\" title=\"bidirectional-references\" src=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2010\/03\/bidirectional-references-300x242.png\" alt=\"\" width=\"300\" height=\"242\" srcset=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2010\/03\/bidirectional-references-300x242.png 300w, https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2010\/03\/bidirectional-references.png 600w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<h3>Navigation-Paths Dictate<\/h3>\n<p>Which one of the 3 possibilities do you pick? The main criteria is how you\u2019re application navigates through the data. For example when you\u2019re accessing the blog posts and only want to know who has written this post, you add a reference to the author. When your always getting a post via its author, you add a collection of posts to the author. And when your application uses both navigation paths, you use a bidirectional relation.<\/p>\n<p>The same applies for the post-tag relationship. When you only want to know which tag a post has, you add a collection to the post with the tags. When you want to know which post have a certain tag, you add a collection of all posts to the tag.<\/p>\n<h3>Bidirectional References: A &#8220;chicken or the egg&#8221; dilemma<\/h3>\n<p>As soon as you have bidirectional references, you cannot avoid a \u2018chicken or the egg\u2019-dilemma. You have to create one instance first and then later assign it. Sometimes it\u2019s easy solvable by adding a factory-method to the parent-class. Like this: <script src=\"https:\/\/gist.github.com\/333317.js?file=factoryExample.cs\"><\/script><noscript><pre><code class=\"language-c# c#\">public Post NewPost()\n{\n\tvar post = new Post(this);\n\tAddPost(post);\n\treturn post;\n}<\/code><\/pre><\/noscript> But often there\u2019s no clear \u2018parent\u2019 or natural order. Especially in n:n relations. For this cases I use my special extension-methods. Let&#8217;s start with a simple class which represents the author and a post <script src=\"https:\/\/gist.github.com\/333317.js?file=author_post_simple.cs\"><\/script><noscript><pre><code class=\"language-c# c#\">    public class Author\n    {\n        private readonly ICollection&lt;Post&gt; _posts = new HashSet&lt;Post&gt;();\n        public void AddPost(Post post)\n        {\n            this._posts.Add(post);\n        }\n\n        public bool RemoveChild(Child item)\n        {\n           return children.Remove(item);\n        }\n\n        public IEnumerable&lt;Post&gt; Posts\n        {\n            get { return _posts; }\n        }\n\n        public string FirstName { get; set; }\n        public string SurName { get; set; }\n\n    }\n\n    public class Post\n    {\n        private Author _author;\n\n        public Post(Author author)\n        {\n            Author = author;\n        }\n\n        public Post()\n        {\n        }\n\n        public Author Author\n        {\n            get { return _author; }\n            set { _author = value; }\n        }\n\n        public string Text\n        {\n            get; set;\n        }\n    }<\/code><\/pre><\/noscript><\/p>\n<p>Then I \u2018upgrade\u2019 the properties and methods with extension-methods to make them relation-aware. Basically on each property\/method I also state what happens to the relationship-partner. Note that you shouldn&#8217;t expose the collections directly. Instead only expose it a read-only IEnumerable and provide additional, domain-specific manipulation-methods. Here\u2019s the code <script src=\"https:\/\/gist.github.com\/333317.js?file=author_post_enhanced.cs\"><\/script><noscript><pre><code class=\"language-c# c#\">\/\/ upgraded author-property\npublic Author Author\n{\n\tget { return _author; }\n\tset { _author = value.AddToParent(this,()=&gt;value.AddPost); }\n}\n\n\/\/ upgraded AddPost-method on the Author-class\n\npublic void AddPost(Post post)\n{\n\t_posts.AddAsChild(post, c =&gt; c.Author = this);\n}\n\npublic bool RemoveChild(Child item)\n{\n        return children.RemoveAsChild(item, c =&gt; c.Parent = null);\n}<\/code><\/pre><\/noscript> Now I can assign, add or remove the object freely, and it&#8217;s ensured that the relation is in a consistent state <script src=\"https:\/\/gist.github.com\/333317.js?file=assigments.cs\"><\/script><noscript><pre><code class=\"language-c# c#\">{\n\t\/\/ when you add the post, its author will be set\n\tvar author = new Author();\n\tvar post = new Post();\n\tauthor.AddPost(post);\n\n\tAssertEqual(author, post.Author);\n}\n{\n\t\/\/ when you set the author of the post, the post is added to the author\n\tvar author = new Author();\n\tvar post = new Post()\n\t\t\t\t   {\n\t\t\t\t\t   Author = author\n\t\t\t\t   };\n\n\tAssertEqual(post, author.Posts.Single());\n\n\t\/\/ when you remove a post, it&#039;s author isn&#039;t set any more\n\tauthor.RemovePost(post);\n\n\tAssertEqual(null, post.Author);\n}<\/code><\/pre><\/noscript><\/p>\n<p>Of course this also works for n:n-relations. For example we start with the relation between tags and posts <script src=\"https:\/\/gist.github.com\/333317.js?file=post_tag_simple.cs\"><\/script><noscript><pre><code class=\"language-c# c#\">public class Post\n{\n\tprivate readonly ICollection&lt;Tag&gt; _tags = new HashSet&lt;Tag&gt;();\n\n\tpublic void AddTag(Tag item)\n\t{\n\t\t_tags.Add(item);\n\t}\n\n\tpublic bool RemoveTag(Tag item)\n\t{\n\t\treturn _tags.Remove(item);\n\t}\n\n\tpublic string Text\n\t{\n\t\tget; set;\n\t}\n\n\tpublic IEnumerable&lt;Tag&gt; Tags\n\t{\n\t\tget { return _tags; }\n\t}\n}\n\npublic class Tag\n{\n\tprivate readonly ICollection&lt;Post&gt; _posts = new HashSet&lt;Post&gt;();\n\n\tpublic void AddPost(Post item)\n\t{\n\t\t_posts.Add(item);\n\t}\n\n\tpublic bool RemovePost(Post item)\n\t{\n\t\treturn _posts.Remove(item);\n\t}\n\n\tpublic IEnumerable&lt;Post&gt; Posts\n\t{\n\t\tget { return _posts; }\n\t}\n}<\/code><\/pre><\/noscript> Again, we \u2018upgrade\u2019 the add and remove method for the relations <script src=\"https:\/\/gist.github.com\/333317.js?file=post_tag_enhanced.cs\"><\/script><noscript><pre><code class=\"language-c# c#\">\/\/ the upgraded post-methods\npublic void AddTag(Tag item)\n{\n\t_tags.AddAsChild(item,t=&gt;t.AddPost(this));\n}\n\npublic bool RemoveTag(Tag item)\n{\n\treturn _tags.RemoveAsChild(item, t =&gt; t.RemovePost(this));\n}\n\n\/\/ the upgraded tag-methods\npublic bool RemovePost(Post item)\n{\n    return _posts.RemoveAsChild(item,p=&gt;p.RemoveTag(this));\n}\n\npublic IEnumerable&lt;Post&gt; Posts\n{\n    get { return _posts; }\n}<\/code><\/pre><\/noscript><\/p>\n<p>And oh wonder, we can freely add and remove and the relation is kept in a consistent state <script src=\"https:\/\/gist.github.com\/333317.js?file=assigments_n_n.cs\"><\/script><noscript><pre><code class=\"language-c# c#\">{\n    \/\/ when you add a tag, the post will be added to the tag\n    var post = new Post();\n    var tag = new Tag();\n    post.AddTag(tag);\n\n    AssertEqual(post,tag.Posts.First());\n}\n{\n    \/\/ when you add a post to a tag, the post will have the tag\n    var tag = new Tag();\n    var post = new Post();\n    tag.AddPost(post);\n\n    AssertEqual(tag, post.Tags.First());\n\n    \/\/ and removing also is bidirectional\n    tag.RemovePost(post);\n\n    AssertEqual(false, post.Tags.Any());\n}<\/code><\/pre><\/noscript><\/p>\n<h3>Implementation of the Extension Methods<\/h3>\n<p>As you can imagine, the implementation isn\u2019t pretty. Especially to avoid endless recursion, some hacks are required. I don\u2019t want to go into detail here (maybe another time). You can take a look at the source yourself. Here it is: \u00a0<a href=\"http:\/\/gist.github.com\/333317#file_relation_management_extensions.cs\">the extension<\/a>, <a href=\"http:\/\/gist.github.com\/333317#file_test_relation_management_extensions.cs\">the tests<\/a>, <a href=\"http:\/\/gist.github.com\/333317#file_tuple.cs\">tuple class<\/a>.<\/p>\n<p>There a certainly cleaner ways to achieve something similar, like special relation-collections. But for my projects this solution is more than enough.<\/p>\n<h3>Conclusion<\/h3>\n<p>Managing object-relations can be very easy or can be pain. When you have reference in one direction it&#8217;s straight forward. But as soon as bidirectional references are required, it can be tricky.<\/p>\n<p>Anyway, critic, tips for improvements or links to good articles on this topic are welcome.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When you design a domain model you normally have lots of 1:n and n:n relations. Many developers are quite familiar how to translate such relations into a relational model. But&hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[126,15,17],"tags":[21,295],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/posts\/1069"}],"collection":[{"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/comments?post=1069"}],"version-history":[{"count":25,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/posts\/1069\/revisions"}],"predecessor-version":[{"id":3842,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/posts\/1069\/revisions\/3842"}],"wp:attachment":[{"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/media?parent=1069"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/categories?post=1069"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/tags?post=1069"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}