Home > Net >  Element from list of object is getting removed when same object is being added to another list
Element from list of object is getting removed when same object is being added to another list

Time:12-14

I'm having some issues with a REST API I'm trying to implement using ASP.NET. So basically the issue I'm having is with the following code :

public async Task<IActionResult> AddUserToTutoringSession(int userId, int tutoringSessionId)
{
    var user = await _context.Users.FindAsync(userId);
    var session =  _context.TutoringSessions.Include(session => session.Students).FirstOrDefault(s => s.Id == tutoringSessionId);

    if (user != null && session != null)
    {
        session.Students.Add(user);
        _context.Update(session);
        _context.SaveChanges();
       
        return Ok();
    }
    return BadRequest();
}

This is an HttpPut method where I'm trying to add a user to a tutoring session. A tutoring session (TutoringSession here) has a list of students (List in this case). The issue that I'm having is the following : let's say that I have two TutoringSessions A and B, if a User is in the list of A and I decide to add it to B, it vanishes from A but now exists in B.

If needed here is the code of both the TutoringSession and the User classes.

public class User
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Username { get; set; }
    [EmailAddress]
    [Required]
    public string Mail { get; set; }
    public string Password { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public string Role { get; set; }
}
public class TutoringSession
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public int RelatedCourseId { get; set; }
    public String Subject { get; set; }
    public DateTime? StartTime { get; set; }
    public DateTime? EndTime { get; set; }
    
    public List<User> Students{ get;set; } 
    public User? Tutor { get; set; }
    public bool IsTutored { get; set; }
}

I've tried to modify it directly using this :

 _context.TutoringSessions.Include(session => session.Students).FirstOrDefault(s => s.Id == tutoringSessionId).Students.Add(user)

But as soon as I call SaveChanges(), it does it again.

I'm sure this is something really silly but it's been almost a day of try/fail and research and I can't find where my error lies, if you guys have any ideas, please let me know!

Edit :

My EF Core version is the 7.0.0

And for the tables here are the SQL scripts that Visual Studio made :

User :

CREATE TABLE [dbo].[User] (
    [Id]                INT            IDENTITY (1, 1) NOT NULL,
    [Username]          NVARCHAR (MAX) NOT NULL,
    [Mail]              NVARCHAR (MAX) NOT NULL,
    [Password]          NVARCHAR (MAX) NOT NULL,
    [Name]              NVARCHAR (MAX) NOT NULL,
    [Surname]           NVARCHAR (MAX) NOT NULL,
    [Role]              NVARCHAR (MAX) NOT NULL,
    [TutoringSessionId] INT            NULL,
    CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_User_TutoringSessions_TutoringSessionId] FOREIGN KEY ([TutoringSessionId]) REFERENCES [dbo].[TutoringSessions] ([Id])
);


GO
CREATE NONCLUSTERED INDEX [IX_User_TutoringSessionId]
    ON [dbo].[User]([TutoringSessionId] ASC);

TutoringSessions :

CREATE TABLE [dbo].[TutoringSessions] (
    [Id]              INT            IDENTITY (1, 1) NOT NULL,
    [relatedCourseId] INT            NOT NULL,
    [Subject]         NVARCHAR (MAX) NOT NULL,
    [StartTime]       DATETIME2 (7)  NULL,
    [EndTime]         DATETIME2 (7)  NULL,
    [TutorId]         INT            NULL,
    [IsTutored]       BIT            NOT NULL,
    CONSTRAINT [PK_TutoringSessions] PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_TutoringSessions_User_TutorId] FOREIGN KEY ([TutorId]) REFERENCES [dbo].[User] ([Id])
);


GO
CREATE NONCLUSTERED INDEX [IX_TutoringSessions_TutorId]
    ON [dbo].[TutoringSessions]([TutorId] ASC);

If you guys need anything more let me know ! :)

CodePudding user response:

The problem is the user can reference only one tutoring session, because in DB schema the relation between User and TutoringSessions is one to many. That means a tutoring sessions can have many user and a user can have one tutoring session.

In your case, you want a relation many to many, that to say a tutoring sessions can have many user and a user can have many tutoring session. To do this, you need to introduce a intermediate table like :

CREATE TABLE [dbo].[Attendee] (
    [TutoringSessionId]     INT            NOT NULL,
    [UserId]                INT            NOT NULL,
    CONSTRAINT [FK_Attendee_TutoringSession] FOREIGN KEY ([TutoringSessionId]) REFERENCES [dbo].[TutoringSession] ([Id]),
    CONSTRAINT [FK_Attendee_User] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User] ([Id])
)

So when a user is register in a session, it's just a new row in the table Attendee and the precedent attendees are keep.


With EF Core 6, you can declare a many to many relation in many ways, but as there are several relation between user and tutoring session, only the fluent way will work :

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<TutoringSession>()
        .HasMany(t => t.Users)
        .WithMany();
}

So EF Core will understand this relation is many to many and will generate the intermediate table on migration.

  • Related