【问题标题】:Dapper many-to-many insertDapper 多对多插入
【发布时间】:2021-06-21 04:53:20
【问题描述】:

我是第一次使用 Dapper,之前习惯直接写 SQL。

我有一个多对多关系的情况,所以我的类看起来像这样:

public class Product
{
    public int Id {get;set;}
    public string otherpropertiesremovedforbrevity Other {get;set;}
    ...
    public List<Attachment> Attachment {get;set;}
}


public class Attachment
{
    public int Id {get;set;}
    public string Name {get;set;}
    public string URL {get;set;}
}

在我的数据库中,我有一个表将它们链接在一起,如下所示;

ProductId 
AttachmentId

(一个复合主键,并且在各自的表中都带有 Fk)。

但我不知道如何执行插入。我有的是下面

  using (var connection = GetConnection)
  {
      connection.Open(); 
      using (var transaction = connection.BeginTransaction())
      {
          string pINSERT = "INSERT INTO prodcat.Product (otherpropertiesremovedforbrevity) " +
                " VALUES (@otherpropertiesremovedforbrevity) RETURNING Id;";

          string sql = "insert into prodcat.AttachmentProductSpecificationLink (ProductSpecificationId, AttachmentId) values(@Id, @AttachmentId)";


          var res = await connection.ExecuteScalarAsync(pINSERT, entity);    
          var arows = await connection.ExecuteAsync(aINSERT, entity.Attachment, transaction);

          transaction.Commit();
          return Convert.ToInt64(res);

      }
  }

但我得到了错误

列“attachmentid”不存在。

所以我显然没有以正确的方式处理这件事。那么我需要做什么才能让它发挥作用呢?

【问题讨论】:

    标签: c# postgresql dapper


    【解决方案1】:

    我相信下面的代码 sn-p 对你有用。

    您应该有 3 个插入语句,分别用于 Product、Attachment 和 AttachmentProductSpecificationLink。在您的示例代码中,您缺少一个。我做了一个假设,你的 aINSERT 应该是 Attachment 表。

    我注意到的另一件事是,您的 ExecuteScalarAsync 正在返回一个对象,因此我使用 ExecuteScalarAsync 来正确转换。

    您的实体(产品类)变量包含附件列表,通常我会执行 ExecuteAsync 并传入列表,因为它是没有返回子句的普通插入。但在您的情况下,您返回的是 Id,所以我选择使用 foreach 循环来迭代插入的附件。

    在 foreach 循环中,我将返回的 ID 返回到变量 attachmentId 中,并将其用于以下插入到 AttachmentProductSpecificationLink 中。由于我们没有返回任何内容,因此我执行了 ExecuteAsync。

    using (var connection = GetConnection())
                {
                    connection.Open();
                    using (var transaction = connection.BeginTransaction())
                    {
                        string pINSERT = "INSERT INTO prodcat.Product (otherpropertiesremovedforbrevity) " +
                              " VALUES (@otherpropertiesremovedforbrevity) RETURNING Id;";
    
                        string aINSERT = "INSERT INTO prodcat.Attachment (Name, URL) " +
                              " VALUES (@Name, @Url) RETURNING Id;";
    
                        string sql = "insert into prodcat.AttachmentProductSpecificationLink (ProductSpecificationId, AttachmentId) values(@Id, @AttachmentId)";
    
    
                        var res = await connection.ExecuteScalarAsync<int>(pINSERT, entity, transaction);
    
                        foreach( var a in entity.Attachment)
                        {
                            var attachmentId = await connection.ExecuteScalarAsync<int>(aINSERT, a, transaction);
    
                            var arows = await connection.ExecuteAsync(sql, new { Id = res, AttachmentId = attachmentId }, transaction);
                        }
    
                        transaction.Commit();
                        return Convert.ToInt64(res);
    
                    }
                }
    

    【讨论】:

    • 这行得通,谢谢。但是有没有什么方法可以避免 Dapper 的循环而只发送整个 Array/List? PS。附件插入没有丢失,数据已经存在于该表中,并且在执行插入之前在业务逻辑中进行了验证。
    【解决方案2】:

    Postgresql 区分大小写,并且您的列名带有大写字母,所以我想您应该在插入语句中引用列名:

    string sql = "insert into prodcat.AttachmentProductSpecificationLink (\"ProductSpecificationId\", \"AttachmentId\") values(@Id, @AttachmentId)";
    

    例如,如果您运行此脚本:

    CREATE TABLE _test("colName" integer);
    
    SELECT * 
    FROM _test 
    WHERE colName = 1;
    

    你会得到一个错误:

    SQL 错误 [42703]:错误:列“colname”不存在
    提示:也许您的意思是引用列“_test.colName”。
    位置:27

    正确的方法是:

    
    SELECT * 
    FROM _test 
    WHERE "colName" = 1;
    

    【讨论】:

    • 对不起,但这没有任何区别,我也有同样的错误。
    猜你喜欢
    • 1970-01-01
    • 2011-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多