CDC Sink: Attachment Handling
-
To store a source column as a RavenDB attachment instead of a document property,
setType = CdcColumnType.Attachmenton the column mapping entry. -
Attachment mappings are typically used for source columns with binary, text, or vector content,
such asbytea,varbinary,text,nvarchar, or pgvectorvectorcolumns. -
Attachment mappings can be used on root tables and embedded tables:
- Root-table attachments are stored on the mapped document.
- Embedded-table attachments are stored on the parent document with a generated
{PropertyName}/{primary-key-values}/name prefix.
-
In this article:
Root table attachments
Given a root SQL table with a binary column:
- SQL
CREATE TABLE files (
id SERIAL PRIMARY KEY,
filename TEXT NOT NULL,
mime_type TEXT NOT NULL,
content BYTEA NOT NULL -- binary attachment
);
Set Type = CdcColumnType.Attachment on the content column entry:
- csharp
new CdcSinkTableConfig
{
CollectionName = "Files",
SourceTableName = "files",
PrimaryKeyColumns = ["id"],
Columns =
[
new CdcColumnMapping() { Column = "id", Name = "Id" },
new CdcColumnMapping() { Column = "filename", Name = "Filename" },
new CdcColumnMapping() { Column = "mime_type", Name = "MimeType" },
new CdcColumnMapping()
{
Column = "content", Name = "file",
// store this column as a RavenDB attachment
Type = CdcColumnType.Attachment
},
]
}
The content column is stored as an attachment named "file" on the document.
The Name value on the attachment mapping becomes the attachment name.
The filename and mime_type columns are stored as regular document properties.
They are not used to set the RavenDB attachment name or content type.
The attachment content type is determined by the runtime value type:
application/octet-stream for binary values, text/plain; charset=utf-8 for text values.
Embedded table attachments
Columns mapped as attachments on embedded tables are stored as attachments on the parent document.
The attachment name is prefixed with the embedded property name and primary key values.
Given a parent products table and a child photos table:
- SQL
CREATE TABLE products (
product_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE photos (
product_id INT NOT NULL REFERENCES products(product_id),
photo_num INT NOT NULL,
caption TEXT,
thumbnail BYTEA, -- binary attachment
PRIMARY KEY (product_id, photo_num)
);
Configure the embedded table with Type = CdcColumnType.Attachment on the attachment column:
- csharp
new CdcSinkEmbeddedTableConfig
{
SourceTableName = "photos",
PropertyName = "Photos",
PrimaryKeyColumns = ["photo_num"],
JoinColumns = ["product_id"],
Columns =
[
new CdcColumnMapping() { Column = "photo_num", Name = "PhotoNum" },
new CdcColumnMapping() { Column = "caption", Name = "Caption" },
new CdcColumnMapping()
{
Column = "thumbnail", Name = "thumb",
Type = CdcColumnType.Attachment
},
]
}
A photo with photo_num = 1 creates an attachment named "Photos/1/thumb" on the parent document.
The prefix "Photos/1/" is generated from the PropertyName and the primary key value.
Attachment naming
Root table attachments
The attachment name is exactly the Name value on the mapping entry with Type = CdcColumnType.Attachment.
Column = "content", Name = "file", Type = CdcColumnType.Attachment
→ Attachment name: "file"
Embedded table attachments
The attachment name is built from the embedded PropertyName, the embedded row's primary key values,
and the mapping Name.
The generated attachment name has this format:
{PropertyName}/{primary-key-value-1}/.../{Name}
where {Name} is the Name value from the attachment column mapping.
PropertyName = "Photos"
PrimaryKeyColumns = ["photo_num"] → photo_num = 1
Column = "thumbnail", Name = "thumb", Type = CdcColumnType.Attachment
→ Attachment name: "Photos/1/thumb"
For composite primary keys, the key values are added in PrimaryKeyColumns order and separated with /:
PrimaryKeyColumns = ["date", "seq"] → date='2024-01', seq=3
→ Attachment name: "Photos/2024-01/3/thumb"
Attachment lifecycle
-
INSERT
A non-null attachment value creates an attachment on the document. -
UPDATE
A non-null attachment value replaces the existing attachment.
If the new value isNULL, the attachment update is skipped and the existing attachment is left unchanged. -
DELETE (embedded item)
When the embedded delete is processed, attachments generated from that embedded item are removed from the parent document. -
DELETE (root document)
When the root document is deleted, the document and its attachments are deleted.