使用 SqlDataSource 綁定預存程序新增資料時,若資料表含 Image 或 VarBinary(MAX) 欄位,精靈產生的參數類型為 Type="Object",運行時拋出:
「sql_variant 類型無法轉換為 Image 類型」 或 「Parameter '@ImageData' exceeds the size limit for the sql_variant datatype」
原因:Object 對應 sql_variant,最大 8000 位元組,不支援大型二進位資料。
<asp:SqlDataSource ID="studentDataSource" runat="server"
ConnectionString="<%$ ConnectionStrings:ConnStr %>"
InsertCommand="spStudentRecordAdd" InsertCommandType="StoredProcedure">
<InsertParameters>
<asp:Parameter Name="StudentName" Type="String" />
<asp:Parameter Name="StudentID" Type="Int32" />
<!-- 移除這行:<asp:Parameter Name="Photo" Type="Object" /> -->
</InsertParameters>
</asp:SqlDataSource>
protected void studentDataSource_Inserting(object sender, SqlDataSourceCommandEventArgs e)
{
// 取得 FileUpload 控件(假設在 FormView 模板中)
FileUpload fu = FormView1.FindControl("FileUpload1") as FileUpload;
byte[] imageData = new byte[0];
if (fu != null && fu.HasFile)
{
imageData = fu.FileBytes;
}
// 關鍵:建立 SqlDbType.Image 參數
SqlParameter photoParam = new SqlParameter("@Photo", SqlDbType.Image);
photoParam.Value = imageData;
// 加入命令參數集合
e.Command.Parameters.Add(photoParam);
}
FormView.ItemInserting 僅能存取 e.Values 字典,無法直接操作 DbCommand 參數集合。SqlDataSource.Inserting 提供 SqlDataSourceCommandEventArgs,暴露 e.Command 完整命令物件,可直接添加強型別參數。<asp:FormView ID="FormView1" runat="server" DataSourceID="studentDataSource" DefaultMode="Insert">
<InsertItemTemplate>
學生姓名: <asp:TextBox ID="txtName" runat="server" Text='<%# Bind("StudentName") %>' /><br/>
學號: <asp:TextBox ID="txtID" runat="server" Text='<%# Bind("StudentID") %>' /><br/>
照片: <asp:FileUpload ID="FileUpload1" runat="server" /><br/>
<asp:LinkButton ID="InsertButton" runat="server" CommandName="Insert" Text="新增" />
</InsertItemTemplate>
</asp:FormView>
<asp:SqlDataSource ID="studentDataSource" runat="server"
OnInserting="studentDataSource_Inserting"
... />
| 方案 | 優點 | 缺點 |
|---|---|---|
| 資料庫儲存二進位 | 交易一致性、備份完整、權限集中 | 資料庫膨脹、備份慢、串流效能差 |
| 檔案系統儲存 + 路徑存 DB | 資料庫輕量、串流快、CDN 友善 | 交易一致性難、檔案權限管理、備份分離 |
| Filestream / FileTable (SQL 2008+) | 結合兩者優點、NTFS 串流、全文檢索 | 設定複雜、需特定版本/版本 |
建議:除非資料量極小且強調 ACID,優先考慮檔案系統或雲端儲存(Blob Storage),資料庫僅存 URL/路徑。
SqlDataSource 處理大型二進位欄位的關鍵在於:移除 Type="Object" 參數,在 Inserting 事件中手動建立 SqlDbType.Image(或 VarBinary)參數並注入 e.Command.Parameters。此技巧同樣適用於 UpdateParameters 與 Updating 事件。
本文出自「王傑瑞的技術部落格」:原文連結