using System; using System.Collections.Generic; using System.Data.Common; using System.Threading; using System.Threading.Tasks; using GB5Shared.DTO.ECM; using GB5Shared.DTO.Framework.Login; using GB5Shared.QueryExecutor; using GB5Shared.Resource.Response; using GB5Shared.Validation; using Newtonsoft.Json; namespace GB5Shared.FileUpload { public class AttachmentDAL : IAttachmentDAL { private readonly IQueryExecutor _QueryExecutor; private readonly IValidation _Validation; public AttachmentDAL(IQueryExecutor QueryExecutor, IValidation Validation) { _QueryExecutor = QueryExecutor; _Validation = Validation; } // ── Save ──────────────────────────────────────────────────── public async Task SaveAttachment(TAttachmentDTO Dto, LoginDTO LoginDTO, DbTransaction Transaction) { try { Dto.CreatedById = LoginDTO.UserId; Dto.CreatedOn = DateTime.UtcNow; Dto.ModifiedById = LoginDTO.UserId; Dto.ModifiedOn = DateTime.UtcNow; // Insert the record await _QueryExecutor.ExecuteAsync(LoginDTO, AttachmentQB.INSERT_ATTACHMENT, Dto, Transaction); // Retrieve the generated ATTACHMENTID via the unique CMSId (works regardless of // whether the PK is an IDENTITY column, sequence, or trigger-assigned value) int attachmentId = await _QueryExecutor.ExecuteScalarAsync( LoginDTO, AttachmentQB.GET_ATTACHMENTID_BY_CMSID, new { Dto.CMSId }, Transaction); return attachmentId; } catch (Exception ex) { throw new Exception(await _Validation.HandleException(ex, ErrorResponse.SaveErrorMessage)); } } // ── Get (raw — used internally by Delete / Download) ────── public async Task GetAttachment(int AttachmentId, LoginDTO LoginDTO) { try { return await _QueryExecutor.QuerySingleAsync( LoginDTO, AttachmentQB.GET_ATTACHMENT_BY_ID, new { AttachmentId }); } catch (Exception ex) { throw new Exception(await _Validation.HandleException(ex, ErrorResponse.GetFetchingMessge)); } } // ── Get detail (API-facing — same shape as GB4 response) ───── public async Task GetAttachmentDetail(int AttachmentId, LoginDTO LoginDTO) { try { return await _QueryExecutor.QuerySingleAsync( LoginDTO, AttachmentQB.GET_ATTACHMENT_DETAIL_BY_ID, new { AttachmentId }); } catch (Exception ex) { throw new Exception(await _Validation.HandleException(ex, ErrorResponse.GetFetchingMessge)); } } // ── List ──────────────────────────────────────────────────── public async Task> ListAttachments(int ObjectId, int ObjectTypeId, LoginDTO LoginDTO) { try { return await _QueryExecutor.QueryAsync( LoginDTO, AttachmentQB.LIST_ATTACHMENTS_BY_OBJECT, new { ObjectId, ObjectTypeId }); } catch (Exception ex) { throw new Exception(await _Validation.HandleException(ex, ErrorResponse.GetFetchingMessge)); } } // ── List by ObjectId only ─────────────────────────────────── public async Task> ListAttachmentsByObjectId(int ObjectId, LoginDTO LoginDTO) { try { return await _QueryExecutor.QueryAsync( LoginDTO, AttachmentQB.LIST_ATTACHMENTS_BY_OBJECTID, new { ObjectId }); } catch (Exception ex) { throw new Exception(await _Validation.HandleException(ex, ErrorResponse.GetFetchingMessge)); } } // ── List by ObjectHeaderId + ObjectId ────────────────────── public async Task> ListAttachmentsByHeaderAndObjectId( int ObjectHeaderId, int ObjectId, LoginDTO LoginDTO) { try { return await _QueryExecutor.QueryAsync( LoginDTO, AttachmentQB.LIST_ATTACHMENTS_BY_HEADER_AND_OBJECT, new { ObjectHeaderId, ObjectId }); } catch (Exception ex) { throw new Exception(await _Validation.HandleException(ex, ErrorResponse.GetFetchingMessge)); } } // ── Update ────────────────────────────────────────────────── public async Task UpdateAttachment(AttachmentUpdateDTO Dto, LoginDTO LoginDTO, DbTransaction Transaction) { try { Dto.ModifiedById = LoginDTO.UserId; Dto.ModifiedOn = DateTime.UtcNow; int rows = await _QueryExecutor.ExecuteAsync( LoginDTO, AttachmentQB.UPDATE_ATTACHMENT, Dto, Transaction); return rows > 0 ? $"Attachment {Dto.AttachmentId} updated successfully." : $"Attachment {Dto.AttachmentId} not found."; } catch (Exception ex) { throw new Exception(await _Validation.HandleException(ex, ErrorResponse.UpdateErrorMessage)); } } // ── Delete ────────────────────────────────────────────────── public async Task DeleteAttachment(int AttachmentId, LoginDTO LoginDTO, DbTransaction Transaction) { try { int rows = await _QueryExecutor.ExecuteAsync( LoginDTO, AttachmentQB.DELETE_ATTACHMENT, new { AttachmentId }, Transaction); return rows > 0 ? $"Attachment {AttachmentId} deleted successfully." : $"Attachment {AttachmentId} not found."; } catch (Exception ex) { throw new Exception(await _Validation.HandleException(ex, ErrorResponse.SaveErrorMessage)); } } // ── Bulk resolve OBJECTID (pre-save upload correlation) ───── public async Task BulkResolveObjectIdAsync( IEnumerable mappings, LoginDTO login, DbTransaction tx, CancellationToken ct) { foreach (var map in mappings) { foreach (var attachmentId in map.AttachmentIds) { await _QueryExecutor.ExecuteAsync( login, AttachmentQB.RESOLVE_OBJECTID, new { AttachmentId = attachmentId, map.ObjectId, map.ObjectTypeId, map.BizTransactionTypeId, ModifiedById = login.UserId }, tx); } } } // ── Orphan fetch — rows with OBJECTID=0 older than threshold ── public async Task> GetOrphanedAttachmentsAsync( DateTime olderThan, int batchSize, LoginDTO login, CancellationToken ct) { return await _QueryExecutor.QueryAsync( login, AttachmentQB.GET_ORPHANED_ATTACHMENTS, new { OlderThan = olderThan, BatchSize = batchSize }); } // ── Batch delete by ID list ────────────────────────────────── public async Task DeleteAttachmentsAsync( IEnumerable attachmentIds, LoginDTO login, DbTransaction tx, CancellationToken ct) { await _QueryExecutor.ExecuteAsync( login, AttachmentQB.DELETE_ATTACHMENTS_BY_IDS, new { Ids = attachmentIds }, tx); } public async Task> ListAttachmentsByHeaderAndObjectHeaderTypeId(int ObjectHeaderTypeId,int ObjectHeaderId,LoginDTO LoginDTO) { try { return await _QueryExecutor.QueryAsync( LoginDTO, AttachmentQB.LIST_ATTACHMENTS_BY_HEADER_AND_OBJECTHEADERTYPE, new { ObjectHeaderTypeId, ObjectHeaderId }); } catch (Exception ex) { throw new Exception(await _Validation.HandleException( ex, ErrorResponse.GetFetchingMessge)); } } public async Task UpdateAttachmentObjectId(AttachmentUpdateDTO Dto, LoginDTO LoginDTO, DbTransaction Transaction) { try { int rows = await _QueryExecutor.ExecuteAsync( LoginDTO, AttachmentQB.UPDATE_ATTACHMENT_OBJECTID, Dto, Transaction); return rows > 0 ? $"Attachment {Dto.AttachmentId} updated successfully." : $"Attachment {Dto.AttachmentId} not found."; } catch (Exception ex) { throw new Exception(await _Validation.HandleException( ex, ErrorResponse.UpdateErrorMessage)); } } // ── SQL (single consumer — AttachmentDAL only, kept private) ─── private static class AttachmentQB { // ── Insert ──────────────────────────────────────────────────── public const string INSERT_ATTACHMENT = @" INSERT INTO TATTACHMENT ( OBJECTTYPEID, OBJECTID, BIZTRANSACTIONTYPEID, SLNO, DOCUMENTSETDETAILID, ATTACHMENTTYPE, DOCUMENTTYPEID, VALIDFROM, VALIDTO, CLASSIFICATIONMARKID, TAGS, CMSID, FOLDERNAME, LINKURL, DISPLAYFILENAME, ATTACHEDFILENAME, REMARKS, STATUS, VERSION, CREATEDBYID, CREATEDON, MODIFIEDBYID, MODIFIEDON, THUMBNAIL, ATTACHMENTOPTION, OBJECTHEADERID, OBJECTHEADERTYPEID, OBJECTHEADERGUID, ROWGUID, MIMETYPE, FILESIZEBYTES ) VALUES ( @ObjectTypeId, @ObjectId, @BizTransactionTypeId, @SlNo, @DocumentSetDetailId, @AttachmentType, @DocumentTypeId, @ValidFrom, @ValidTo, @ClassificationMarkId, @Tags, @CMSId, @FolderName, @LinkUrl, @DisplayFileName, @AttachedFileName, @Remarks, @Status, @Version, @CreatedById, @CreatedOn, @ModifiedById, @ModifiedOn, @Thumbnail, @AttachmentOption, @ObjectHeaderId, @ObjectHeaderTypeId, @ObjectHeaderGuid, @RowGuid, @MimeType, @FileSizeBytes );"; // Retrieve the generated ATTACHMENTID using the unique CMSId (within the same transaction) public const string GET_ATTACHMENTID_BY_CMSID = @" SELECT ATTACHMENTID FROM TATTACHMENT WHERE CMSID = @CMSId;"; // ── Get single (raw — used internally by Delete / Download) ── public const string GET_ATTACHMENT_BY_ID = @" SELECT ATTACHMENTID AS AttachmentId, OBJECTTYPEID AS ObjectTypeId, OBJECTID AS ObjectId, BIZTRANSACTIONTYPEID AS BizTransactionTypeId, SLNO AS SlNo, DOCUMENTSETDETAILID AS DocumentSetDetailId, ATTACHMENTTYPE AS AttachmentType, DOCUMENTTYPEID AS DocumentTypeId, VALIDFROM AS ValidFrom, VALIDTO AS ValidTo, CLASSIFICATIONMARKID AS ClassificationMarkId, TAGS AS Tags, CMSID AS CMSId, FOLDERNAME AS FolderName, LINKURL AS LinkUrl, DISPLAYFILENAME AS DisplayFileName, ATTACHEDFILENAME AS AttachedFileName, REMARKS AS Remarks, STATUS AS Status, VERSION AS Version, CREATEDBYID AS CreatedById, CREATEDON AS CreatedOn, MODIFIEDBYID AS ModifiedById, MODIFIEDON AS ModifiedOn, THUMBNAIL AS Thumbnail, ATTACHMENTOPTION AS AttachmentOption, OBJECTHEADERID AS ObjectHeaderId, OBJECTHEADERTYPEID AS ObjectHeaderTypeId, OBJECTHEADERGUID AS ObjectHeaderGuid, ROWGUID AS RowGuid, MIMETYPE AS MimeType, FILESIZEBYTES AS FileSizeBytes FROM TATTACHMENT WHERE ATTACHMENTID = @AttachmentId;"; // ── Get single detail (API-facing — same shape as GB4 response) ─ // Index required: TATTACHMENT(ATTACHMENTID) public const string GET_ATTACHMENT_DETAIL_BY_ID = @" SELECT TA.CMSID AS Id, TA.DISPLAYFILENAME AS FileName, TA.DISPLAYFILENAME AS ActualFileName, NULL AS FileContent, NULL AS RelativePath, NULL AS DownLoadUrl, NULL AS ViewUrl, TA.ATTACHMENTTYPE AS Type, TA.ATTACHMENTID AS AttachmentId, FORMAT(TA.CREATEDON, 'yyyy/MM/dd HH:mm') AS CreatedOn, TA.CREATEDBYID AS CreatedById, ISNULL(U.USERNAME, '') AS CreatedBy, TA.OBJECTTYPEID AS ObjectTypeId, TA.OBJECTID AS ObjectId, NULL AS ClientId, TA.VALIDFROM AS ValidFrom, TA.VALIDTO AS ValidTo, TA.STATUS AS Status, TA.DOCUMENTTYPEID AS DocumentTypeId, ISNULL(DT.DOCUMENTTYPENAME, 'NONE') AS DocumentTypeName, ISNULL(DT.ISVALIDITY, 0) AS IsValidity, TA.DOCUMENTSETDETAILID AS DocumentSetDetailId, TA.CLASSIFICATIONMARKID AS ClassificationMarkId, CASE WHEN TA.CLASSIFICATIONMARKID = -1 THEN 'NONE' ELSE '' END AS ClassificationMarkName, '0' AS OwnSave, '0' AS OwnEdit, '0' AS OwnDelete, '0' AS OwnRead, '0' AS OthSave, '0' AS OthEdit, '0' AS OthDelete, '0' AS OthRead, TA.ATTACHMENTOPTION AS AttachmentOption, TA.TAGS AS Guid, TA.FOLDERNAME AS FolderName, TA.MIMETYPE AS MimeType, TA.FILESIZEBYTES AS FileSizeBytes FROM TATTACHMENT TA LEFT JOIN MUSER U ON U.USERID = TA.CREATEDBYID LEFT JOIN MDOCUMENTTYPE DT ON DT.DOCUMENTTYPEID = TA.DOCUMENTTYPEID WHERE TA.ATTACHMENTID = @AttachmentId;"; // ── List by object ──────────────────────────────────────────── // Indexes required: TATTACHMENT(OBJECTID, OBJECTTYPEID, STATUS) public const string LIST_ATTACHMENTS_BY_OBJECT = @" SELECT TA.CMSID AS Id, TA.DISPLAYFILENAME AS FileName, TA.DISPLAYFILENAME AS ActualFileName, NULL AS FileContent, NULL AS RelativePath, NULL AS DownLoadUrl, NULL AS ViewUrl, TA.ATTACHMENTTYPE AS Type, TA.ATTACHMENTID AS AttachmentId, FORMAT(TA.CREATEDON, 'yyyy/MM/dd HH:mm') AS CreatedOn, TA.CREATEDBYID AS CreatedById, ISNULL(U.USERNAME, '') AS CreatedBy, TA.OBJECTTYPEID AS ObjectTypeId, TA.OBJECTID AS ObjectId, NULL AS ClientId, TA.VALIDFROM AS ValidFrom, TA.VALIDTO AS ValidTo, TA.STATUS AS Status, TA.DOCUMENTTYPEID AS DocumentTypeId, ISNULL(DT.DOCUMENTTYPENAME, 'NONE') AS DocumentTypeName, ISNULL(DT.ISVALIDITY, 0) AS IsValidity, TA.DOCUMENTSETDETAILID AS DocumentSetDetailId, TA.CLASSIFICATIONMARKID AS ClassificationMarkId, CASE WHEN TA.CLASSIFICATIONMARKID = -1 THEN 'NONE' ELSE '' END AS ClassificationMarkName, '0' AS OwnSave, '0' AS OwnEdit, '0' AS OwnDelete, '0' AS OwnRead, '0' AS OthSave, '0' AS OthEdit, '0' AS OthDelete, '0' AS OthRead, TA.ATTACHMENTOPTION AS AttachmentOption, TA.TAGS AS Guid, TA.FOLDERNAME AS FolderName, TA.MIMETYPE AS MimeType, TA.FILESIZEBYTES AS FileSizeBytes FROM TATTACHMENT TA LEFT JOIN MUSER U ON U.USERID = TA.CREATEDBYID LEFT JOIN MDOCUMENTTYPE DT ON DT.DOCUMENTTYPEID = TA.DOCUMENTTYPEID WHERE TA.OBJECTID = @ObjectId AND TA.OBJECTTYPEID = @ObjectTypeId AND TA.STATUS <> 2 ORDER BY TA.CREATEDON DESC;"; // ── List by ObjectId only ───────────────────────────────────── // Index required: TATTACHMENT(OBJECTID, STATUS) public const string LIST_ATTACHMENTS_BY_OBJECTID = @" SELECT TA.CMSID AS Id, TA.DISPLAYFILENAME AS FileName, TA.DISPLAYFILENAME AS ActualFileName, NULL AS FileContent, NULL AS RelativePath, NULL AS DownLoadUrl, NULL AS ViewUrl, TA.ATTACHMENTTYPE AS Type, TA.ATTACHMENTID AS AttachmentId, FORMAT(TA.CREATEDON, 'yyyy/MM/dd HH:mm') AS CreatedOn, TA.CREATEDBYID AS CreatedById, ISNULL(U.USERNAME, '') AS CreatedBy, TA.OBJECTTYPEID AS ObjectTypeId, TA.OBJECTID AS ObjectId, NULL AS ClientId, TA.VALIDFROM AS ValidFrom, TA.VALIDTO AS ValidTo, TA.STATUS AS Status, TA.DOCUMENTTYPEID AS DocumentTypeId, ISNULL(DT.DOCUMENTTYPENAME, 'NONE') AS DocumentTypeName, ISNULL(DT.ISVALIDITY, 0) AS IsValidity, TA.DOCUMENTSETDETAILID AS DocumentSetDetailId, TA.CLASSIFICATIONMARKID AS ClassificationMarkId, CASE WHEN TA.CLASSIFICATIONMARKID = -1 THEN 'NONE' ELSE '' END AS ClassificationMarkName, '0' AS OwnSave, '0' AS OwnEdit, '0' AS OwnDelete, '0' AS OwnRead, '0' AS OthSave, '0' AS OthEdit, '0' AS OthDelete, '0' AS OthRead, TA.ATTACHMENTOPTION AS AttachmentOption, TA.TAGS AS Guid, TA.FOLDERNAME AS FolderName, TA.MIMETYPE AS MimeType, TA.FILESIZEBYTES AS FileSizeBytes FROM TATTACHMENT TA LEFT JOIN MUSER U ON U.USERID = TA.CREATEDBYID LEFT JOIN MDOCUMENTTYPE DT ON DT.DOCUMENTTYPEID = TA.DOCUMENTTYPEID WHERE TA.OBJECTID = @ObjectId AND TA.STATUS <> 2 ORDER BY TA.CREATEDON DESC;"; // ── List by ObjectHeaderId + ObjectId ──────────────────────── // Index required: TATTACHMENT(OBJECTHEADERID, OBJECTID, STATUS) public const string LIST_ATTACHMENTS_BY_HEADER_AND_OBJECT = @" SELECT TA.CMSID AS Id, TA.DISPLAYFILENAME AS FileName, TA.DISPLAYFILENAME AS ActualFileName, NULL AS FileContent, NULL AS RelativePath, NULL AS DownLoadUrl, NULL AS ViewUrl, TA.ATTACHMENTTYPE AS Type, TA.ATTACHMENTID AS AttachmentId, FORMAT(TA.CREATEDON, 'yyyy/MM/dd HH:mm') AS CreatedOn, TA.CREATEDBYID AS CreatedById, ISNULL(U.USERNAME, '') AS CreatedBy, TA.OBJECTTYPEID AS ObjectTypeId, TA.OBJECTID AS ObjectId, NULL AS ClientId, TA.VALIDFROM AS ValidFrom, TA.VALIDTO AS ValidTo, TA.STATUS AS Status, TA.DOCUMENTTYPEID AS DocumentTypeId, ISNULL(DT.DOCUMENTTYPENAME, 'NONE') AS DocumentTypeName, ISNULL(DT.ISVALIDITY, 0) AS IsValidity, TA.DOCUMENTSETDETAILID AS DocumentSetDetailId, TA.CLASSIFICATIONMARKID AS ClassificationMarkId, CASE WHEN TA.CLASSIFICATIONMARKID = -1 THEN 'NONE' ELSE '' END AS ClassificationMarkName, '0' AS OwnSave, '0' AS OwnEdit, '0' AS OwnDelete, '0' AS OwnRead, '0' AS OthSave, '0' AS OthEdit, '0' AS OthDelete, '0' AS OthRead, TA.ATTACHMENTOPTION AS AttachmentOption, TA.TAGS AS Guid, TA.FOLDERNAME AS FolderName, TA.MIMETYPE AS MimeType, TA.FILESIZEBYTES AS FileSizeBytes FROM TATTACHMENT TA LEFT JOIN MUSER U ON U.USERID = TA.CREATEDBYID LEFT JOIN MDOCUMENTTYPE DT ON DT.DOCUMENTTYPEID = TA.DOCUMENTTYPEID WHERE TA.OBJECTHEADERID = @ObjectHeaderId AND (TA.OBJECTID = @ObjectId OR @ObjectId = -1) AND TA.STATUS <> 2 ORDER BY TA.CREATEDON DESC;"; // ── Update ──────────────────────────────────────────────────── public const string UPDATE_ATTACHMENT = @" UPDATE TATTACHMENT SET DISPLAYFILENAME = @DisplayFileName, REMARKS = @Remarks, DOCUMENTTYPEID = @DocumentTypeId, VALIDFROM = @ValidFrom, VALIDTO = @ValidTo, CLASSIFICATIONMARKID = @ClassificationMarkId, STATUS = @Status, TAGS = @Tags, OBJECTHEADERID = @ObjectHeaderId, MODIFIEDBYID = @ModifiedById, MODIFIEDON = @ModifiedOn WHERE ATTACHMENTID = @AttachmentId;"; // ── Delete ──────────────────────────────────────────────────── public const string DELETE_ATTACHMENT = @" DELETE FROM TATTACHMENT WHERE ATTACHMENTID = @AttachmentId;"; // ── Resolution — update OBJECTID after entity save ──────────── // Called inside the entity's open DB transaction so the update is // rolled back automatically if the entity save fails. public const string RESOLVE_OBJECTID = @" UPDATE TATTACHMENT SET OBJECTID = @ObjectId, OBJECTTYPEID = @ObjectTypeId, BIZTRANSACTIONTYPEID = @BizTransactionTypeId, MODIFIEDBYID = @ModifiedById, MODIFIEDON = GETUTCDATE() WHERE ATTACHMENTID = @AttachmentId;"; // ── Orphan cleanup — fetch unresolved rows older than threshold ─ // Index required: IX_TATTACHMENT_OBJECTID_CREATEDON (see migration) public const string GET_ORPHANED_ATTACHMENTS = @" SELECT TOP (@BatchSize) ATTACHMENTID AS AttachmentId, CMSID AS CMSId, FOLDERNAME AS FolderName, DISPLAYFILENAME AS DisplayFileName FROM TATTACHMENT WHERE OBJECTID = 0 AND CREATEDON < @OlderThan ORDER BY CREATEDON ASC;"; // Dapper expands IEnumerable @Ids into IN (id1, id2, ...) public const string DELETE_ATTACHMENTS_BY_IDS = @" DELETE FROM TATTACHMENT WHERE ATTACHMENTID IN @Ids;"; public const string LIST_ATTACHMENTS_BY_HEADER_AND_OBJECTHEADERTYPE = @" SELECT TA.CMSID AS Id, TA.DISPLAYFILENAME AS FileName, TA.DISPLAYFILENAME AS ActualFileName, NULL AS FileContent, NULL AS RelativePath, NULL AS DownLoadUrl, NULL AS ViewUrl, TA.ATTACHMENTTYPE AS Type, TA.ATTACHMENTID AS AttachmentId, FORMAT(TA.CREATEDON, 'yyyy/MM/dd HH:mm') AS CreatedOn, TA.CREATEDBYID AS CreatedById, ISNULL(U.USERNAME, '') AS CreatedBy, TA.OBJECTTYPEID AS ObjectTypeId, TA.OBJECTID AS ObjectId, NULL AS ClientId, TA.VALIDFROM AS ValidFrom, TA.VALIDTO AS ValidTo, TA.STATUS AS Status, TA.DOCUMENTTYPEID AS DocumentTypeId, ISNULL(DT.DOCUMENTTYPENAME, 'NONE') AS DocumentTypeName, ISNULL(DT.ISVALIDITY, 0) AS IsValidity, TA.DOCUMENTSETDETAILID AS DocumentSetDetailId, TA.CLASSIFICATIONMARKID AS ClassificationMarkId, CASE WHEN TA.CLASSIFICATIONMARKID = -1 THEN 'NONE' ELSE '' END AS ClassificationMarkName, '0' AS OwnSave, '0' AS OwnEdit, '0' AS OwnDelete, '0' AS OwnRead, '0' AS OthSave, '0' AS OthEdit, '0' AS OthDelete, '0' AS OthRead, TA.ATTACHMENTOPTION AS AttachmentOption, TA.TAGS AS Guid, TA.FOLDERNAME AS FolderName, TA.MIMETYPE AS MimeType, TA.FILESIZEBYTES AS FileSizeBytes FROM TATTACHMENT TA LEFT JOIN MUSER U ON U.USERID = TA.CREATEDBYID LEFT JOIN MDOCUMENTTYPE DT ON DT.DOCUMENTTYPEID = TA.DOCUMENTTYPEID WHERE TA.OBJECTHEADERTYPEID = @ObjectHeaderTypeId AND TA.OBJECTHEADERID = @ObjectHeaderId AND ISNULL(TA.STATUS, 0) <> 2 ORDER BY TA.CREATEDON DESC;"; public const string UPDATE_ATTACHMENT_OBJECTID = @" UPDATE TATTACHMENT SET OBJECTID = @ObjectId WHERE OBJECTTYPEID = @ObjectTypeId AND ATTACHMENTID = @AttachmentId;"; } } }