1

I have been playing with Onion Architecture, DDD and Specification pattern. There are many implementations with Entity Framework, where domain entities going right in the DBSet<> of the context. For me, it's not ok, at least because of many-to-many relationships. Let's say we have the next dbo's:


    public class Post
    {
        public int PostId { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }

        public List<PostTag> PostTags { get; set; }
    }

    public class Tag
    {
        public string TagId { get; set; }

        public string Name { get; set; }

        public List<PostTag> PostTags { get; set; }
    }

    public class PostTag
    {
        public int PostId { get; set; }
        public Post Post { get; set; }

        public string TagId { get; set; }
        public Tag Tag { get; set; }
    }

The problem is that entity models should not know anything about the Post.PostTag because it's a details of implementation of the persistence layer. For instance, I could change storage to JSON objects, and it is no longer a need for an intermediate table. So, ideally, my entity models will be looking like that:

    public class Post
    {
        public int PostId { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }

        public List<Tag> Tags { get; set; }
    }

    public class Tag
    {
        public string TagId { get; set; }

        public string Name { get; set; }
    }

Or it goes even worse, if we decide to add some new property to PostTag, for example


    public class PostTag
    {
        ...
        public bool IsActive { get; set; }
        ...
    }

Then, it will affect the Tag when considering this example with entity model.

public class Post
    {
        public int PostId { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }

        public List<Tag> Tags { get; set; }
    }

    public class Tag
    {
        public string TagId { get; set; }
        public bool IsActive { get; set; } // this is added
        public string Name { get; set; }
    }

Because of this, I want to have both entity and dbo models. When I implementing PostRepository, which is located at the infrastructure layer, and I want to expose the IQueriable<Post> Query(). Here are the real problems started. The cause of problems is that the application layer, who is the consumer of the repository can operate only within the Post entity, but not PostDbo. And they can be different. Because of that, I can't write a specification for this entity. So, the main question is how to implement the Repository pattern which can expose such Query() method, while having separated entity and dbo models, without serious effect on performance and optimality of queries.


Or, maybe, specification pattern is just a huge overhead which is more harmful then useful. The reason is that when you decide to change entity framework to something else, you should to write your own query provider for Expression<Func<TEntity>>. What do you think?


Maybe I'm wrong with something, so correct me, please. I will be grateful for reasonable answers.

Thanks

Fran
  • 6,440
  • 1
  • 23
  • 35
  • You don't need to define the join table if it is truly a join table. i.e. no columns other than the 2 FK's https://www.entityframeworktutorial.net/code-first/configure-many-to-many-relationship-in-code-first.aspx. Once you add columns it becomes a full blown entity – Fran Mar 06 '20 at 20:07
  • @Fran for now, this isn't working for EF Core [link](https://learn.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key#many-to-many). EF 6 supports many-to-many relationships without intermediate table, while in EF Core this isn't implemented yet. That's exactly the one we want to avoid by abstraction: need to know how the data stored and what processes executing while doing CRUD. Basically, this question isn't all about many-to-many relationships – Balianytsia Artem Mar 08 '20 at 21:15

0 Answers0