我假设 FileTable 你实际上是指 FileStream。关于这一点的几点说明:
- 如果您的文件实际上是文件,则最好使用此功能
- 这些文件平均应大于 1mb - 尽管此规则可能存在例外情况,但如果它们平均小于 1mb,则最好适当地使用 a
VARBINARY(MAX)
或XML
数据类型。如果您的图像平均非常小(只有几 KB),请考虑使用VARBINARY(MAX)
列。
- 访问这些文件将需要一个打开的事务,并且数据库已正确配置
FILESTREAM
- 您可以通过告诉 SQL Server 您要直接访问文件来绕过正常的 SQL 引擎/数据库文件数据访问方法,从而获得一些显着优势,但这并不意味着直接访问文件系统上的文件并尝试这样做可以打破 SQL 对这些文件的管理(事务一致性、跟踪、锁定等)。
- 如果您确实需要 SQL,则很可能通过使用 CDN 并将图像 URL 存储在表中来更好地服务您的用例。您可以使用它
FILESTREAM
来执行此操作(请参阅下面的代码示例以了解一种实现),但是除非您将图像存储在浏览器可以正确缓存的其他位置(我的示例没有这样做),否则您将为每个请求敲击您的 SQL 服务器) - 如果您将它们存储在其他地方以便在浏览器中呈现,您不妨将它们存储在那里(一旦它们被复制到其他驱动器/磁盘/位置,这些图像就不会具有事务一致性) .
说了这么多,下面是一个如何FILESTREAM
使用 ADO.NET 访问数据的示例:
public static string connectionString = ...; // get your connection string from encrypted config
// assumes your FILESTREAM data column is called Img in a table called ImageTable
const string sql = @"
SELECT
Img.PathName(),
GET_FILESTREAM_TRANSACTION_CONTEXT()
FROM ImageTagble
WHERE ImageId = @id";
public string RetreiveImage(int id)
{
string serverPath;
byte[] txnToken;
string base64ImageData = null;
using (var ts = new TransactionScope())
{
using (var conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.Add("@id", SqlDbType.Int).Value = id;
using (SqlDataReader rdr = cmd.ExecuteReader())
{
rdr.Read();
serverPath = rdr.GetSqlString(0).Value;
txnToken = rdr.GetSqlBinary(1).Value;
}
}
using (var sfs = new SqlFileStream(serverPath, txnToken, FileAccess.Read))
{
// sfs will now work basically like a FileStream. You can either copy it locally or return it as a base64 encoded string
using (var ms = new MemoryStream())
{
sfs.CopyTo(ms);
base64ImageData = Convert.ToBase64String(ms.ToArray());
}
}
}
ts.Complete();
// assume this is PNG image data, replace PNG with JPG etc. as appropraite. Might store in table if it will vary...
return "data:img/png;base64," + base64ImageData;
}
}
显然,如果您有很多图像要像这样处理,这不是一个理想的方法 - 不要尝试将 SQL Server 实例制作成您应该使用 CDN 的......但是,如果您真的有其他充分的理由,您应该尝试在单个请求/事务中获取尽可能多的图像(例如,如果您知道您在页面上显示 50 个图像,则使用单个事务范围获取所有 50 个图像,不要使用 50 个事务范围- 此代码不会处理)。