Re: Mapping Many-to-Many once forever

92 views
Skip to first unread message

Jimmy Bogard

unread,
Sep 23, 2020, 8:22:48 AM9/23/20
to automapper-users
The easiest thing to do here is avoid the "many-to-many" magic in the ORM. Explicitly model the junction table in the middle of those relationships, and your problems disappear:

On 9/23/2020 3:34:03 AM, Moheb Yarahmadi <moheb.y...@gmail.com> wrote:

# Automapper Many-to-Many mapping

Hi everyone, I'm struggling with mapping my related entities in automapper for many-to-many relationship.

*here is the situation:*

I'm working on an API and I need to get my responses with DTOs , if I use pure entities in my requests and responses it will work well without any issue but with DTOs it will not work.

Course Entity:

```c#
public class Course
{
    [Column("CourseId")]
    public Guid Id {get; set:}
    public string Title {get; set:}
    
    public ICollection<CourseCategory> CourseCategories {get; set;}
}
```

Category Entity:

```c#
public class Category
{
 [Column("CategoryId")]   
 public int Id {get; set;}
 public string Title {get; set;}
 
 public ICollection<CourseCategory> CourseCategories {get; set;}
}
```

CourseCategory Entity:

```c#
public class CourseCategory
{
    public Guid CourseId {get; set;}
    public Course Course {get; set;}
    
    public int CategoryId {get; set;}
    public Category Category {get; set;}
}
```

Here is my DTOs

CourseDto:

```c#
public class CourseDto
{
    public Guid Id {get; set;}
    public string Title {get; set;}
    
    public IList<CategoryDto> Categories {get; set;}
}
```

CategoryDto:

```c#
public class CategoryDto
{
    public int Id {get; set;}
    public string Title {get; set;}
    
    public IList<CourseDto> Courses {get; set;} // It's not good
}
```

This is where I got stuck with mapping.

My mapping profile for Automapper:

```c#
public MappingProfile()
{
    CreateMap<Course, CourseDto>()
        .ForMember(dto => dto.Categories, opt =>
                   opt.MapFrom(x => x.CourseCategories.Select(y => y.Category).ToList()));
    
    CreateMap<Category, CategoryDto>()
        .ForMember(dto => dto.Courses, opt =>
                   opt.MapFrom(x => x.CourseCategories.Select(y => y.Course).ToList()));
}
```

My Repositories:

CategoryRepository

```c#
public async Task<IReadOnlyList<Category>> GetAllCategoriesAsync(bool trackChanges) =>
            await FindAll(trackChanges)
                .Include(c => c.CourseCategories)
                .ThenInclude(cc => cc.Category)
                .OrderBy(c => c.Title)
                .ToListAsync();

public async Task<Category> GetCategoryAsync(int categoryId, bool trackChanges) =>
            await FindByCondition(c => c.Id.Equals(categoryId), trackChanges)
                .Include(c => c.CourseCategories)
                .ThenInclude(cc => cc.Category)
                .SingleOrDefaultAsync();
```

CourseRepository

```c#
public async Task<IReadOnlyList<Course>>GetAllCoursesAsync(bool trackChanges) =>
            await FindAll(trackChanges)
                .Include(c => c.CourseCategories)
                .ThenInclude(cc => cc.Category)
                .OrderBy(c => c.Title)
                .ToListAsync();

        
public async Task<Course>GetCourseAsync(Guid courseId, bool trackChanges) =>
            await FindByCondition(c => c.Id.Equals(courseId), trackChanges)
                .Include(cc => cc.CourseCategories)
                .ThenInclude(c => c.Category)
                .SingleOrDefaultAsync();
```

Now if I send a GET request through the **/api/courses** I will get the response correctly

```json
{
        "id": "c9d4c053-49b6-410c-bc78-2d54a9991870",
        "title": "Course Tilte",
        "categories": [
            {
                "id": 1,
                "title": "Category 01",
                "courses": [] // this not what I want
            },
            {
                "id": 2,
                "title": "Category 02",
                "courses": [] // this not what I want
            }
        ],
}
```

But on the other side I can't get list of courses for specific category through **/api/categories** and I will get these errors :

```
fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1]
      An unhandled exception has occurred while executing the request.
System.InvalidOperationException: The Include path 'CourseCategories->Category' results in a cycle. Cycles are not allowed in no-tracking queries. Either use a tracking query or remove the cycle.
```

```json
{
    "StatusCode": 500,
    "Message": "Internal Server Error." // my errors are not implemented yet. this is default
}
```

sorry for the long long story but I had no choice. I want to get  access to my relations through the other side as well and need solution to how can I set these relations while I'm posting a new course. **Thank you in advance**

--
You received this message because you are subscribed to the Google Groups "AutoMapper-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to automapper-use...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/automapper-users/758a7d8d-a065-4255-9716-a7dc2f029949n%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages