1

I want to insert data into multiple related tables, I searched, but everything I've found is insert data into multiple tables that aren't related. I have two tables User and OrchardTable, both are related by the user Id, so the primary key of the User table is the Id, which is generated as an identity on the database, and the foreign key of the table OrchardTable is the User Id.

This is from my controller

[HttpPost]
public ActionResult post([FromBody] Models.Users u)
{
    using (Models.OrchardAdminContext db = new Models.OrchardAdminContext())
    {
        Models.User oUser = new Models.User();

        Models.OrchardTable userOrchar = new Models.OrchardTable();

        oUser.Name = u.Name;
        oUser.Email = u.Email;
        db.User.Add(oUser);
        db.SaveChanges();
        
        var idUser = db.OrchardTable.Where(x => x.email = oUser.Email).FirstOrDefault();
        userOrchar.IdUser = idUser.Id;
        userOrchar.orchardUbication = u.ubication;
        db.OrchardTable.Add(userOrchard);
        db.SaveChanges();
    }
    return Ok();
}

So, the code above do: first adds an user to the User table, on the SQL Server Management Studio the Id of each user is an identity therefore when the data is saved the Id is generated and through the mail the id of the user is recovered to make the relation between the tables User and OrchardTable by the Id.

I think this is a way of do it, but not the best. Besides the main question, I want to know if there are a better and correct way to do the insert.

Any help is appreciated.

UPDATE Stored procedure to insert into the table User and return the Id from the same instert:

GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE spUserInsert 
   @name varchar(20),
   @email varchar(100)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

-- Insert statements for procedure here
   insert into user(name, email) values (@name, @email);
   DECLARE @Id INT  
   SET @Id=@@IDENTITY  
   SELECT @Id AS id
END
GO

So if I'm not mistaken, the idea is to create an SP to insert and return the id of that insert, then with the id send it to another SP where it is inserted into OrchardTable. But now when I call it from the controller it doesn't seem to work because no saved record shows up in the database.

The controller:

    [HttpPost]
    public ActionResult post([FromBody] Models.Users u)
    {
        using (Models.OrchardAdminContext db = new Models.OrchardAdminContext())
        {
            Models.User oUser = new Models.User();

            Models.OrchardTable userOrchar = new Models.OrchardTable();

            oUsuar.Name = u.Name;
            oUsuar.Email = u.Email;
            
            var idUserReg = db.User.FromSqlRaw("Execute spUserInsert @name, @email", oUsuar.Name, oUsuar.Email);

            db.SaveChanges();

        }
        return Ok();
    }

I tested the stored procedure on Sql Server and works, but on the controller not, and I don't know why on the controller din't work. Again, any help is appreciated.

5
  • 3
    Just my 2p, doing this from client code means multiple round trips to the database and a lookup using the email (is there an index on email - probably a wide column so not really appropriate). You'd be better off encapsulating this process in a stored procedure, will require a single call to the database, pass the required arguments as parameters, it can insert your user and using the returned identity immediately insert your OrchardTable also. Commented Mar 31, 2021 at 20:34
  • 1
    This is another way I did to solve this kind of issue. I created a sequence table for the Id and created a SQL function for increasing the sequence and getting the one increased as the Id. So before Instantiating the User and the OrchardTable, call the function getting the Id and you use the Id to save the data of the classes. Commented Mar 31, 2021 at 22:58
  • @Stu I think I got your idea, I updated the content of the question with the stored procedure. Commented Apr 1, 2021 at 3:17
  • I don't know why on the controller din't work Hi @Daniel,can you explain more details?e.g. what is your error message do you have?Besides,please share your model design to us. Commented Apr 1, 2021 at 7:26
  • @Rena, Hi, not exactly an error, the thing is that when I send the POST request through Postman the stored procedure is called but it does nothing, therefore nothing is saved in the database. Commented Apr 1, 2021 at 18:25

2 Answers 2

1

With respect to the procedure to encapsulate the insert, this is what I had in mind you could do

create procedure UserInsert 
@Name varchar(20),
@Email varchar(100)
<@anyOtherParameters>
as
set nocount, xact_abort on

declare @Id int

begin tran
    insert into [user]([name], email)
    values (@Name, @Email);

    set @Id=Scope_Identity();

    insert into OrchardTable (Id, <othercolumns?>)
    values (@Id, @OtherParams?);
commit tran
go

You only need to make one call from code, the procedure will insert the user, get the identity and then insert this Id into the OrchardTable

If you need to include any other data just pass as paramters also and use for the insert - if you only want a row with the corresponding ID then just leave as a single insert for the Id.

Sign up to request clarification or add additional context in comments.

Comments

1

Try this:

var pName = new SqlParameter("@name", oUsuar.Name);
var pEmail = new SqlParameter("@email", oUsuar.Email);
            
var idUserReg = db.DataBase.ExecuteSqlCommand("Exec spUserInsert @name, @email", 
new[] { pName, pEmail });

1 Comment

Your solution also helped me, but instead of used ExecuteSqlCommand I use FromSqlRaw.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.