简体   繁体   中英

Dapper many-to-many insert

I am using Dapper for the first time, I'm previously used to just writing my SQL directly.

I have a situation where I have a many-to-many relationship so that my classes look like this:

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;}
}

In my DB I have a table to link them together which looks like this;

ProductId 
AttachmentId

(A composite primary key and both with Fk to their repective tables).

But I don't know how to perform the insert. What I have is below

  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);

      }
  }

But I get the error

column "attachmentid" does not exist.

So I'm obviously not going about this in the right manner. So what do I need to do in order to get this to work?

Postgresql is case sensitive and you have column names with capital letters, so I guess you should quote the column names in insert statement:

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

For example if you run this script:

CREATE TABLE _test("colName" integer);

SELECT * 
FROM _test 
WHERE colName = 1;

You will get an error:

SQL Error [42703]: ERROR: column "colname" does not exist
Hint: Perhaps you meant to reference the column "_test.colName".
Position: 27

The correct way would be:


SELECT * 
FROM _test 
WHERE "colName" = 1;

I believe the code snippet below will work for you.

You should have 3 insert statements, for Product, Attachment and AttachmentProductSpecificationLink. In your sample code you are missing one. I made the assumption, that your aINSERT should be for the Attachment table.

Another thing I noticed, Your ExecuteScalarAsync was returning an object, so I used ExecuteScalarAsync<int> instead to cast correctly.

Your entity ( Product class) variable contains a List of Attachments, Normally I would perform an ExecuteAsync and pass in the List because it is plain Inserts with no returning Clause. But in your case you are returning the Ids so I opted to use a foreach loop to iterate over the attachments for the inserts.

Within the foreach loop I return the returning ID into the variable attachmentId and use it for the following insert into AttachmentProductSpecificationLink. Since we aren't return anything I perform an 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);

                }
            }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM