Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

parent child IQueryable mapping: recursion depth support #785

Open
Azaferany opened this issue Sep 28, 2023 · 3 comments
Open

parent child IQueryable mapping: recursion depth support #785

Azaferany opened this issue Sep 28, 2023 · 3 comments
Labels
enhancement New feature or request

Comments

@Azaferany
Copy link

Azaferany commented Sep 28, 2023

Describe the bug
when i want map parent class with prop of list of child and child class have prop of parent class (simple parent child relationship) and use IQueryable mapping mappings not generated and "Stack overflow" error occurre on build

To Reproduce

public class CarDto
{
    public string Name { get; set; }
    public List<SeatDto> Seats { get; set; }
}
public class SeatDto { 
    public int Position { get; set; }
    public CarDto Car { get; set; }
}

public class Car
{
    public string Name { get; set; }
    public List<Seat> Seats { get; set; }
}
public class Seat
{
    public int Position { get; set; }
    public Car Car { get; set; }
}
[Mapper]
public static partial class CarMapper
{
    public static partial IQueryable<CarDto> ProjectToDto(this IQueryable<Car> q);
}

Expected behavior
i thing its stuck in loop of mapping but i think would be great if ignoring Car property on Seat class mapping or atlest it could be ignord by MapperIgnoreSourceAttribute (MapperIgnoreSourceAttribute & MapperIgnoreTargetAttribute not working on IQueryable mappings )

Environment (please complete the following information):

  • Mapperly Version: 3.2.0
  • .NET Version: .NET 6.0.102
  • Target Framework: .net6.0
  • IDE: Rider 2023
  • OS: windows 10
    e following information):**
  • Mapperly Version: 3.2.0
  • .NET Version: .NET 6.0.102
  • Target Framework: .net6.0
  • IDE: Rider 2023
  • OS: windows 10

Additional context
MapperIgnoreSourceAttribute & MapperIgnoreTargetAttribute not working on IQueryable mappings

@latonz latonz added the bug Something isn't working label Sep 29, 2023
@latonz
Copy link
Contributor

latonz commented Sep 29, 2023

Does it work if you define your mapper like follows:

[Mapper]
public static partial class CarMapper
{
    public static partial IQueryable<CarDto> ProjectToDto(this IQueryable<Car> q);
    
    [MapperIgnoreSource(nameof(Seat.Car))]
    private static partial SeatDto MapSeat(this Seat source);
}

(IQueryable projection mappings pick up configurations in the same mapper for types which need to be mapped by the IQueryable projection mapping).

@tvardero
Copy link

tvardero commented Oct 2, 2023

I also have got an stack overflow. With those models:

public class Node
{
    public int Id { get; init; }
    
    public int? ParentNodeId { get; init; }
    public Node? ParentNode { get; init; }
    
    public Node[] ChildNodes { get; init; }
}

public class NodeDto
{
    public int Id { get; init; }
    
    public int? ParentNodeId { get; init; }
    
    public NodeDto[] ChildNodes { get; init; }
}

public static partial IQueryable<NodeDto> ProjectToDto(this IQueryable<Node> query);

I assume that mapper does not know how deep he needs to project child nodes:

// assumption:
return query.Select(n1 => new NodeDto
        {
            Id = n1.Id,
            ParentNodeId = n1.ParentNodeId,
            ChildNodes = n1.ChildNodes.Select(n2 => new NodeDto
            {
                Id = n2.Id,
                ParentNodeId = n2.ParentNodeId,
                ChildNodes = n2.ChildNodes.Select(n3 => new NodeDto
                {
                    Id = n3.Id,
                    ParentNodeId = n3.ParentNodeId,
                    ChildNodes = n3.ChildNodes.Select(n4 => new ) // and so on
                })
            })
        })

For now I don't see any solution to map it using only mapper. Probably children entities need to be mapped outside of query.

@TimothyMakkison
Copy link
Collaborator

TimothyMakkison commented Oct 13, 2023

(IQueryable projection mappings pick up configurations in the same mapper for types which need to be mapped by the IQueryable projection mapping).

Does Mapperly do this? I know IQueryable can reuse user implemented methods.

I had the following generate with a user implemented method. Not sure what should go in MapSeat.

[Mapper]
public static partial class Mapper
{
    public static partial IQueryable<CarDto> ProjectToDto(this IQueryable<Car> q);

    private static SeatDto MapSeat(this Seat source) => throw new NotImplementedException();
}

// generates
public static partial class Mapper
{
    public static partial global::System.Linq.IQueryable<global::Riok.Mapperly.Sample.CarDto> ProjectToDto(this global::System.Linq.IQueryable<global::Riok.Mapperly.Sample.Car> q)
    {
#nullable disable
        return System.Linq.Queryable.Select(q, x => new global::Riok.Mapperly.Sample.CarDto()
        {
            Name = x.Name,
            Seats = global::System.Linq.Enumerable.ToList(global::System.Linq.Enumerable.Select(x.Seats, x1 => MapSeat(x1))),
        });
#nullable enable
    }
}

Does EF handle recursive queries (uses a CTE?). Perhaps this would be best done manually with raw SQL. How do Automapper/mapster handle this?

We probably need a separate issue for enhanced loop detection. Perhaps a MaxDepth property could be added? See here

@latonz latonz changed the title parent child IQueryable mapping parent child IQueryable mapping: recursion depth support Mar 11, 2024
@latonz latonz added enhancement New feature or request and removed bug Something isn't working labels Apr 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants