简体   繁体   中英

EF Core Automapper Recursive Query

I have a self-referencing class

public class Project {
    public Guid Id { get; set; }
    public string Name { get; set; }
    public Guid? ParentId { get; set; }    
}

I have setup a psotgres database with ef core and automapper all working.

My Dto looks as follows:

public class ProjectDto {
    public Guid Id { get; set; }
    public string Name { get; set; }
    public ICollection<ProjectPathEntry> Path { get; set; } = new HashSet<ProjectPathEntry>();
}

with the helper-dto

public class ProjectPathEntry {
    public Guid Id { get; set; }
    public string Name { get; set; }
}

The problem comes now with the automapper config:) The Id and Name automaticly get mapped by convention but the Path obviously cannot get mapped directly.

I can fill the Path with a separate query:

var projectPath = await dbContext.Projects.FromSqlInterpolated(
    $@"WITH recursive project(search_id, id, name) AS (
        SELECT p.""Id"", p.""Id"", p.""Name""
        FROM public.""Projects"" p

        UNION ALL

        SELECT p.""Id"", p2.id, p2.name
        FROM public.""Projects"" p, project p2
        WHERE p.""ParentProjectId"" = p2.search_id
    )
    SELECT proj.*
    FROM project
    JOIN public.""Projects"" proj on proj.""Id"" = project.id
    WHERE search_id = {project.Id}
        AND id != {project.Id}"
).ProjectTo<ProjectPathEntry>(mapper.ConfigurationProvider)
.ToListAsync(cancellationToken);

projectPath.Reverse();
project.Path = projectPath;

can I somehow embedd this query in my automapper config? Or is there a possibility to add a SQL-View to my pg-database and map it via ef entity configuration?

I solved my problem by adding a View to my Database:

CREATE VIEW "ProjectPathView"("ProjectId", "SortId", "Id", "Name") AS
    WITH RECURSIVE project(search_id, sort_id, id, name) AS (
        SELECT p."Id",
            1,
            p."Id",
            p."Name"
FROM "Projects" p
    UNION ALL
    SELECT p."Id",
        p2.sort_id + 1,
        p2.id,
        p2.name
    FROM "Projects" p,
        project p2
    WHERE p."ParentProjectId" = p2.search_id
)
SELECT project.search_id AS "ProjectId",
    project.sort_id AS "SortId",
    proj."Id",
    proj."Name"    
FROM project
JOIN "Projects" proj ON proj."Id" = project.id;

Then I created a model

public class ProjectPathEntry
{
    public Guid ProjectId { get; set; }
    public long SortId { get; set; }
    public Guid Id { get; set; }
    public string Name { get; set; }
}

which represents my View. In the EF configuration I set the ToView("ProjectPathView") setting. I then added the relationship to my base Model

public class Project {
    ...
        public virtual ICollection<ProjectPathEntry> Path { get; set; } = new HashSet<ProjectPathEntry>();
    ...
}

and set the HasMany Configuration

builder.HasMany(p => p.Path)
       .WithOne()
       .HasForeignKey(p => p.ProjectId);

Then the Path Property on my ProjectDto can be mapped automaticly via Automapper.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM