【问题标题】:What is the proper way to insert in and join these tables?插入和加入这些表的正确方法是什么?
【发布时间】:2022-01-10 06:26:56
【问题描述】:

我有三个表:Clients、Products 和 Orders

客户:

ClientID - PK
ClientName

产品:

ProductID - PK
ProductName
ProductQuantity
ProductSize
Comments

订单:

OrderID - PK
StartDate
FinishDate
Delivered
Billed

关于我的问题,我有一些不同的答案,即如何加入这些表。我应该为 3 个表的 id 创建第 4 个表还是在订单表中加入客户和产品。事情是一个客户有一个或多个产品的订单。 请指教。

代码更新!

我现在有这个代码,它只适用于客户和产品:

using (var con = new SqlConnection(@"Data Source = GAMEWORK\SQLEXPRESS; Initial Catalog = Tida; Integrated Security = True"))
            using (var cmd = new SqlCommand("InsertClients", con) { CommandType = CommandType.StoredProcedure })
            using (var cmd2 = new SqlCommand("InsertProducts", con) { CommandType = CommandType.StoredProcedure })
            using (var cmd3 = new SqlCommand("InsertOrders", con) { CommandType = CommandType.StoredProcedure })
            {

                //-----------This works perfect
                if (TextBoxClientNou.Enabled)
                {
                    cmd.Parameters.AddWithValue("@NumeClient", TextBoxClientNou.Text);
                }

                else
                {
                    cmd.Parameters.AddWithValue("@NumeClient", TextBoxClientNou.Text);
                }

                var IDClientParameter = cmd.Parameters.Add("@IDClient", SqlDbType.Int);
                IDClientParameter.Direction = ParameterDirection.Output;
                con.Open();
                cmd.ExecuteNonQuery();
                var IDClient = (int)IDClientParameter.Value;
                con.Close();

                cmd2.Parameters.Add("@Denumire", SqlDbType.NVarChar, 50);
                cmd2.Parameters.Add("@Cantitate", SqlDbType.Int, 50);
                cmd2.Parameters.Add("@Dimensiuni", SqlDbType.NVarChar, 50);
                cmd2.Parameters.Add("@Comentarii", SqlDbType.NVarChar, 50);
                var IDProductParameter = cmd2.Parameters.Add("@IDProdus", SqlDbType.Int);
                IDProductParameter.Direction = ParameterDirection.Output;

                con.Open();

                foreach (ListViewItem item in ListaProduse.Items)
                {
                    cmd2.Parameters["@Denumire"].Value = item.Text;
                    cmd2.Parameters["@Cantitate"].Value = item.SubItems[1].Text;
                    cmd2.Parameters["@Dimensiuni"].Value = item.SubItems[1].Text;
                    cmd2.Parameters["@Comentarii"].Value = item.SubItems[1].Text;
                    cmd2.ExecuteNonQuery();
                }  //-----------------------Perfect


                //-------This does not work
                cmd3.Parameters.Add("@ClientID", SqlDbType.Int).Value = IDClient;
                cmd3.Parameters.Add("@ProductID", SqlDbType.Int);
                cmd3.Parameters.Add("@DataInceput", SqlDbType.NVarChar).Value = dateTimePicker1.Text;
                cmd3.Parameters.Add("@DataSfarsit", SqlDbType.NVarChar).Value = dateTimePicker2.Text;
                cmd3.Parameters.Add("@Facturata", SqlDbType.NVarChar, 50).Value = factstatus;
                cmd3.Parameters.Add("@Livrata", SqlDbType.NVarChar, 50).Value = livstatus;

                cmd3.Parameters.Clear(); //---Only inserts the last product in the order table
                var IDProdus = (int)IDProductParameter.Value;
                cmd3.Parameters.AddWithValue("@ClientID", IDClient);
                cmd3.Parameters.AddWithValue("@ProductID", IDProdus);
                cmd3.Parameters.AddWithValue("@DataInceput", dateTimePicker1.Text);
                cmd3.Parameters.AddWithValue("@DataSfarsit", dateTimePicker2.Text);
                cmd3.Parameters.AddWithValue("@Facturata", factstatus);
                cmd3.Parameters.AddWithValue("@Livrata", livstatus);
                cmd3.ExecuteNonQuery();
                //---------------------------
            }

还有这个存储过程:

CREATE PROCEDURE [dbo].[InsertOrders]
    
    @ClientID int,
    @ProductID int,
    @DataInceput nvarchar(50),
    @DataSfarsit nvarchar(50),
    @Facturata nvarchar(50),
    @Livrata nvarchar(50)

AS
    
    BEGIN
        INSERT INTO Comenzi (ClientID, ProductID, DataInceput,DataSfarsit,Factstatus,Livstatus) VALUES (@ClientID, @ProductID, @DataInceput,@DataSfarsit,@Facturata,@Livrata);
    END

问题出在 cmd3.parameters.Clear() 上。如果我不使用它,我会收到以下错误:

System.Data.SqlClient.SqlException: 'Procedure or function InsertOrders has too many arguments specified.'

如果我使用它,无论我添加多少,只有表单中的最后一个产品会插入到订单表中。另外,如果我使用 cmd3.ExecuteNonQuery();在 foreach 循环中,它会增加订单 ID 并为列表中的每个产品创建和订购,这是我不想要的。

【问题讨论】:

  • 我认为在订单表中加入客户和产品是个好主意,除非您需要更频繁地检索这些记录。如果您多次访问相同的记录,第 4 表可能是提高 sql 性能的好主意。
  • 要获得灵感,请查看this simple model 供学生使用。它在订单和产品之间有一个表格。
  • 这是关于关系数据库中的表还是关于 C# 中的类?
  • 顾问回答:视情况而定。这取决于您的实际场景,但在我的经验中,enigmativity's answer 的观点是现实世界场景中最常用的。这应该是您问题的公认答案。
  • 这听起来真的像你通过编辑完全改变了你在这个问题中寻找的东西。

标签: c# sql


【解决方案1】:

如果我假设正确,您现有的表格如下所示:

public class Client
{
    public int Id;
    public string Name;
}

public class Product
{
    public int Id;
    public string Name;
    public int Quantity;
    public decimal Size;
    public string Comments;
}

public class Order
{
    public int Id;
    public DateTime StartDate;
    public DateTime FinishDate;
    public DateTime Delivered;
    public DateTime Billed;
}

...那么这是我的初步建议:

使用 FK 将 Order 修改为 Client,这样您就知道是谁下了订单。

public class Order
{
    public int Id;
    public int ClientId;
    public DateTime StartDate;
    public DateTime FinishDate;
    public DateTime Delivered;
    public DateTime Billed;
}

那么,由于订单是交易的不可变记录,它不应链接到Product。因此,创建一个新的 OrderProduct 表,将 FK 包含到 Order 中,并在每次创建订单时复制所有字段

public class OrderProduct
{
    public int Id;
    public int OrderId;
    public string Name;
    public int Quantity;
    public decimal Size;
    public string Comments;
}

现在,如果您有这样的产品目录:

var products = new[]
{
    new Product()
    {
        Id = 1,
        Name = "Foo"
        Quantity = 500,
    }
};

...如果您将1“Foo”出售给“Fred”,那么交易可能如下所示:

var product =
    products
        .Where(p => p.Name == "Foo")
        .First();

var client = new Client() { Id = 1, Name = "Fred" };

var order = new Order()
{
    Id = 1,
    ClientId = client.Id,
    StartDate = DateTime.Now
};

var orderProduct = new OrderProduct()
{
    Id = product.Id,
    OrderId = order.Id,
    Name = product.Name,
    Quantity = 1
};

product.Quantity -= 1;

【讨论】:

    【解决方案2】:

    我是否正确理解您有一份可以订购的产品清单,并且一个订单总是由一个客户完成?

    然后我会为客户创建一个包含他们的数据和一个 ID 的表,然后我会创建一个包含不同产品的表并为每个产品指定一个 ID。我会为每个订单提供客户 ID 和产品 ID,以及您可能拥有的其他数据(开始日期、结束日期等)(自己的订单 ID 也会有所帮助)

    这样,您可以轻松地通过客户或产品找到每个订单。但请确保 id 没有改变。

    【讨论】:

    • 是的,一个订单由一个客户完成,他可以订购一个或多个产品。但没有清单,它是定制产品。我尝试了这两种变体,但问题是订单 ID 会增加,我将为相同的客户和产品拥有三个不同的订单,而不是为拥有两个或更多产品的客户提供一个订单 ID。
    • @Chriss_1982 在您的问题上面您说,您有一个产品表,其中每个产品都有一个 id,所以我的解决方案应该仍然有效。我认为一个问题是一个订单在我的解决方案中只能有一个产品,为此我会给出一个带有多个 Id 的字符串而不是产品 ID,其中包含客户想要的数量。您可以根据需要将它们分开,只要您以后仍然能够将它们分开即可。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-14
    • 2012-01-13
    • 2018-08-28
    相关资源
    最近更新 更多