Добавление одной ко многим записям в хранимой процедуре - PullRequest
0 голосов
/ 11 ноября 2018

Мне нужна помощь кого-то, кто знает SQL, потому что это проблема, выходящая за рамки моих навыков работы с SQL.Вот мои таблицы:

CREATE TABLE [dbo].[Orders]
(
    id              INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    customerName    VARCHAR(30) NOT NULL,
    customerAddress VARCHAR(30) NOT NULL,
    submitDate      DATE NOT NULL,
    realizationDate DATE,
    deliveryTypeId  INT NOT NULL

    FOREIGN KEY(deliveryTypeId) REFERENCES deliveryTypes(id)
);

CREATE TABLE [dbo].[OrderItems]
(
    id              INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    orderId         INT NOT NULL,
    productId       INT NOT NULL,
    productQuantity INT,

    FOREIGN KEY(orderId) REFERENCES Orders(id), 
    FOREIGN KEY(productId) REFERENCES Products(id)
);

Мне нужно создать хранимую процедуру, которая вставляет в две таблицы в базе данных одну во многие связанные записи (на самом деле это действительно часть привязок «многие ко многим», но янужно добавить только эти две таблицы).В моем приложении (.NET) мне нужно передать одну запись "Orders" и одну или несколько записей "OrderItems".

Мои проблемы:

  • Если я вставлю «Порядок», я не буду знать, какое значение установить в OrderItems -> orderId.Я нашел функцию SCOPE_IDENTITY, но я не знаю, как ее использовать в моем случае.
  • Как мне вставить OrderItems записи в таблицу, если я не знаю, сколько их будет?Я только знаю, что их может быть один или несколько.
  • Я не знаю, как вызвать процедуру, получающую много OrderItems от уровня приложения, и какие аргументы я должен объявить в хранимой процедуре

Я действительно ценю всю помощь, потому что я столкнулся с этой проблемой несколько часов, и я действительно не знаю, как это сделать.

РЕДАКТИРОВАТЬ: Это код, который я пришелдо сих пор:

CREATE PROCEDURE spAddOrder
    (@customerName    VARCHAR(30),
     @customerAddress VARCHAR(30),
     @submitDate      DATE,
     @deliveryTypeId  INT
    -- I don't know how to pass many OrderItems rows as argument
)
AS
BEGIN
    INSERT INTO Orders(customerName, customerAddress, submitDate, deliveryTypeId)
    VALUES (@customerName, @customerAddress, @submitDate, @deliveryTypeId)

    SELECT SCOPE_IDENTITY() AS orderId

    -- I don't know how to do it for unknown number of rows
    INSERT INTO OrderItems(orderId, productId, productQuantity)
    VALUES (@orderId, @productId, @productQuantity)
END;
GO

1 Ответ

0 голосов
/ 11 ноября 2018

Хотя этот вопрос можно считать слишком широким и поэтому не по теме, он хорошо написан и описывает проблему, с которой сталкиваются многие неопытные разработчики - поэтому я думаю, что он заслуживает ответа.
Итак, давайте разберем его по составляющим:

  1. Q: Как вернуть значение столбца identity после вставки?
    A: SQL Server предоставляет несколько способов сделать это, самый простой из них, вероятно, будет scope_identity, но лучшим будет использование предложения output.

  2. Q: Как отправить несколько строк в хранимую процедуру?
    A: Использовать табличный параметр .

Теперь посмотрим, как именно мы это сделаем.

Первое, что нам нужно сделать, это создать пользовательский тип таблицы, который будет использоваться для параметра с табличным значением - так:

CREATE TYPE [dbo].[Udt_OrderItems] AS TABLE
(
    productId       int NOT NULL,
    productQuantity int,
);
GO

Затем мы можем создать хранимую процедуру, используя этот тип в качестве параметра с табличным значением. Мы также отправим детали заказа в виде скалярных параметров в хранимую процедуру:

CREATE PROCEDURE stp_InsertOrderWithItems
(
    @customerName    varchar(30),
    @customerAddress varchar(30),
    @submitDate      date,
    @realizationDate date,
    @deliveryTypeId  int,
    @orderItems dbo.Udt_OrderItems readonly -- Table valued parameters must be readonly
)
AS

    DECLARE @Ids AS TABLE (orderId int NOT NULL) -- for the output clause

    INSERT INTO dbo.Orders (customerName, customerAddress, submitDate, realizationDate, deliveryTypeId)
    OUTPUT inserted.Id INTO @Ids
    VALUES(@customerName, @customerAddress, @submitDate, @realizationDate, @deliveryTypeId)

    INSERT INTO dbo.OrderItems (orderId, productId, productQuantity)
    SELECT orderId, productId, productQuantity
    FROM @orderItems
    CROSS JOIN @Ids -- We only have one value in @Ids so cross join is safe
GO

Что касается части c #, это зависит от того, как вы подключаетесь к базе данных - я покажу пример базовой версии ADO.Net:

using(var con = new SqlConnection(connectionString))
{
    using(var cmd = new SqlCommand(con, "stp_InsertOrderWithItems"))
    {
        var dt = new DataTable()
        dt.Columns.Add("productId", typeof(int));
        dt.Columns.Add("productQuantity", typeof(int));

        // populate data table here

        cmd.Parameters.Add("@customerName", SqlDbType.VarChar, 30).Value = customerName;
        // all the other scalar parameters here...
        cmd.Parameters.Add(@orderItems, SqlDbType.Structured).Value = dt;

        con.Open();
        cmd.ExecuteNonQuery();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...