Home > Enterprise >  How can I get many to many relationship records with using Linq on Entity Framework 6.4?
How can I get many to many relationship records with using Linq on Entity Framework 6.4?

Time:08-05

I have a database which I gave details of it down below.

There are projects, also modules and versions which are related with projects. Although, every version doesn't contain every module.

How can I get those records with using Linq on Entity Framework 6.4 ?

Here is the JSON result that I want to get.

{
  "id": 1,
  "name": "Super Project",
  "versions": [
    {
      "id": 1,
      "name": "Basic",
      "availableModules": []
    },
    {
      "id": 2,
      "name": "Advenced",
      "availableModules": [
        {
          "id": 1,
          "name": "3 Users"
        },
        {
          "id": 2,
          "name": "50Gb Space"
        }
      ]
    }
    ....
    ....
    
  ]
}

Here is the database query:

SELECT 
    p.Id ProjectID, p.Name ProjectName, pv.Name VersionName, 
    pm.Name ModuleName
FROM
    Project p
INNER JOIN
    ProjectVersion pv ON pv.ProjectId = p.Id
LEFT JOIN 
    ProjectModuleAvailableVersions mav ON mav.ProjectVersionId = pv.Id
LEFT JOIN
    ProjectModule pm ON pm.ID = mav.ProjectModuleId

There is a screenshot of the results of that query:

enter image description here

There is the database structure if you want to try:

IF OBJECT_ID('ProjectModuleAvailableVersions') IS NOT NULL 
     DROP TABLE ProjectModuleAvailableVersions

IF OBJECT_ID('ProjectModule') IS NOT NULL 
     DROP TABLE ProjectModule

IF OBJECT_ID('ProjectVersion') IS NOT NULL 
     DROP TABLE ProjectVersion

IF OBJECT_ID('Project') IS NOT NULL 
     DROP TABLE Project


CREATE TABLE dbo.Project
(
    Id INT IDENTITY(1,1) NOT NULL,
    Name VarChar(100) NULL,
    CONSTRAINT PK_Project PRIMARY KEY CLUSTERED (Id)
)
GO

CREATE TABLE dbo.ProjectVersion
(
    Id INT IDENTITY(1,1) NOT NULL,
    ProjectId INT,
    Name Varchar(100) NULL,
    CONSTRAINT PK_ProjectVersion PRIMARY KEY CLUSTERED (Id),
    CONSTRAINT FK_ProjectVersion_ProjectId 
        FOREIGN KEY (ProjectId) REFERENCES Project (Id) 
            ON DELETE CASCADE
)
GO

CREATE TABLE dbo.ProjectModule
(
    Id INT IDENTITY(1,1) NOT NULL,
    ProjectId INT,
    Name Varchar(100) NULL,
    CONSTRAINT PK_ProjectModule PRIMARY KEY CLUSTERED (Id),
    CONSTRAINT FK_ProjectModule_ProjectId 
        FOREIGN KEY (ProjectId) REFERENCES Project (Id) 
            ON DELETE CASCADE
)
GO

CREATE TABLE dbo.ProjectModuleAvailableVersions
(
    Id INT IDENTITY(1,1) NOT NULL,
    ProjectVersionId INT,
    ProjectModuleId INT,
    CONSTRAINT PK_ProjectModuleAvailableVersions PRIMARY KEY CLUSTERED (Id)
)
GO

INSERT INTO Project Values ('Super Project')           -- ID: 1
INSERT INTO Project Values ('Fantastic Project')       -- ID: 2

INSERT INTO ProjectVersion Values (1, 'Basic')         -- ID: 1
INSERT INTO ProjectVersion Values (1, 'Advanced')      -- ID: 2
INSERT INTO ProjectVersion Values (2, 'Modern')        -- ID: 3
INSERT INTO ProjectVersion Values (2, 'Professional')  -- ID: 4
INSERT INTO ProjectVersion Values (2, 'Cloud')         -- ID: 5 

INSERT INTO ProjectModule Values (1, '3 Users')        -- ID: 1
INSERT INTO ProjectModule Values (1, '50Gb Space')     -- ID: 2
INSERT INTO ProjectModule Values (2, 'SyncData')       -- ID: 3 
INSERT INTO ProjectModule Values (2, 'Export Data')    -- ID: 4
INSERT INTO ProjectModule Values (2, 'Import Data')    -- ID: 5

INSERT INTO ProjectModuleAvailableVersions Values (2,1)  -- Advanced - 3 Users
INSERT INTO ProjectModuleAvailableVersions Values (2,2)  -- Advanced - 50Gb
INSERT INTO ProjectModuleAvailableVersions Values (3,3)  -- Modern - SynData
INSERT INTO ProjectModuleAvailableVersions Values (4,3)  -- Professional - SyncData
INSERT INTO ProjectModuleAvailableVersions Values (4,4)  -- Professional - ExprotData
INSERT INTO ProjectModuleAvailableVersions Values (5,3)  -- Professional - SyncData
INSERT INTO ProjectModuleAvailableVersions Values (5,4)  -- Professional - ExprotData
INSERT INTO ProjectModuleAvailableVersions Values (5,5)  -- Professional - ImportData

Edit: My classes are here

public class ProjectDto : IDto
{
  public int Id { get; set; }
  public string? Name { get; set; }
  public List<ProjectVersionDto>? Versions { get; set; }
}

public class ProjectVersionDto : IDto
{
  public int Id { get; set; }
  public string? Name { get; set; }
  public List<ProjectModuleDto> Modules { get; set; }
}

public class ProjectModuleDto : IDto
{
  public int ID { get; set; }
  public string? Name { get; set; }
}

And that's how I tried to do it.

using CrmContext context = new CrmContext();
var result = from p in context.Project
    select new ProjectDto()
    {
        Id = p.ID,
        Name = p.Name,
        Versions = (from pv in context.ProjectVesion
            where pv.Project == p.ID
            join av in context.ProjectModuleAvailableVersions on pv.ID equals av.Version
            select new ProjectVersionDto
            {
            Modules = (from pm in context.ProjectModule
                        where pm.Project == p.ID
                        join an in context.ProjectModuleAvailableVersions on pv.ID equals an.Version
                        select new ProjectModuleDto
                        {
                        ID = 0,
                        Name = null,
                        }
                ).ToList()
            }).ToList()
    };
return result.ToList();

CodePudding user response:

Your problem seems to me to be with join operations.

var result = from p in context.Project
select new ProjectDto()
{
    Id = p.Id,
    Name = p.Name,
    Versions = (from pv in context.ProjectVesion.OrderBy(o => o.ProjectId)
        where p.Id == pv.ProjectId
        select new ProjectVersionDto
        {
        Id = pv.Id,
        Name = pv.Name,
        Modules = (from pm in context.ProjectModule
            where pm.ProjectId == pv.ProjectId
            join pav in context.ProjectModuleAvailableVersions on pm.Id equals pav.ModuleId
            where pav.VersionId == pv.Id
            select new ProjectModuleDto
            {
            Id = pm.Id,
            Name = pm.Name,
            }).ToList()
        }).ToList()
};
  return result.ToList();

The order of nested objects is as follows;

ProjectDto > Versions > Modules

If you dont make a left join to the ProjectModuleAvailableVersions table, you will have no problems.

Have a nice day.

  • Related