這是場景:如何使用SqlDataReader在普通的舊C#對象中使用BLOB提供的流?
- 我們存儲文件,例如,相對較大的文檔(10-300MB),在我們的MSSQL數據庫的斑點中。
- 我們有一個非常小的域模型,因此我們使用乾淨的SqlDataReader方法來存儲我們的存儲庫,而不是ORM,以避免不必要的依賴關係。
- 我們希望在ASP.NET/ASP.NET MVC網頁的服務器上下文中使用對象。
- 我們不希望的斑臨時存儲字節[],以避免服務器
所以,我一直在做的就是實現自己的SqlBlobReader高內存使用情況。它繼承了Stream和IDisposable,並且在實例化過程中,我們必須提供一個SqlCommand,其中包含一個返回一行的查詢,當然這是我們想要流的blob。然後我的C#域對象可以有一個Stream類型的屬性,它返回一個SqlBlobReader實現。當流式傳輸到ASP.net MVC中的FileContentStream等時,可以使用此流。
它會立即執行帶SequentialAccess的ExecuteReader以啓用從MSSQL服務器流式傳輸blob。這意味着在使用它時我們必須小心地儘快處理流,並且當需要時我們總是懶惰地實例化SqlBlobReader。在我們的域對象中使用庫調用。
我的問題則是:
- 這是使用SqlDataReader的,而不是一個ORM時對普通的舊域對象實現斑點流的一個聰明的辦法?
- 我不是ADO.NET專家,執行看起來是否合理?
SqlBlobReader.cs:
using System;
using System.Data;
using System.Data.SqlClient;
using System.IO;
namespace Foo
{
/// <summary>
/// There must be a SqlConnection that works inside the SqlCommand. Remember to dispose of the object after usage.
/// </summary>
public class SqlBlobReader : Stream
{
private readonly SqlCommand command;
private readonly SqlDataReader dataReader;
private bool disposed = false;
private long currentPosition = 0;
/// <summary>
/// Constructor
/// </summary>
/// <param name="command">The supplied <para>sqlCommand</para> must only have one field in select statement, or else the stream won't work. Select just one row, all others will be ignored.</param>
public SqlBlobReader(SqlCommand command)
{
if (command == null)
throw new ArgumentNullException("command");
if (command.Connection == null)
throw new ArgumentException("The internal Connection cannot be null", "command");
if (command.Connection.State != ConnectionState.Open)
throw new ArgumentException("The internal Connection must be opened", "command");
dataReader = command.ExecuteReader(CommandBehavior.SequentialAccess);
dataReader.Read();
this.command = command; // only stored for disposal later
}
/// <summary>
/// Not supported
/// </summary>
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
/// <summary>
/// Not supported
/// </summary>
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override int Read(byte[] buffer, int index, int count)
{
long returned = dataReader.GetBytes(0, currentPosition, buffer, 0, buffer.Length);
currentPosition += returned;
return Convert.ToInt32(returned);
}
/// <summary>
/// Not supported
/// </summary>
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return false; }
}
public override long Length
{
get { throw new NotSupportedException(); }
}
public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
protected override void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
if (dataReader != null)
dataReader.Dispose();
SqlConnection conn = null;
if (command != null)
{
conn = command.Connection;
command.Dispose();
}
if (conn != null)
conn.Dispose();
disposed = true;
}
}
base.Dispose(disposing);
}
public override void Flush()
{
throw new NotSupportedException();
}
}
}
在Repository.cs:
public virtual Stream GetDocumentFileStream(int fileId)
{
var conn = new SqlConnection {ConnectionString = configuration.ConnectionString};
var cmd = new SqlCommand
{
CommandText =
"select DocumentFile " +
"from MyTable " +
"where Id = @Id",
Connection = conn,
};
cmd.Parameters.Add("@Id", SqlDbType.Int).Value = fileId;
conn.Open();
return new SqlBlobReader(cmd);
}
在DocumentFile.cs:
public Stream GetStream()
{
return repository.GetDocumentFileStream(Id);
}
在DocumentController.cs:
// A download controller in ASP.net MVC 2
[OutputCache(CacheProfile = "BigFile")]
public ActionResult Download(int id)
{
var document = repository.GetDocument(id);
return new FileStreamResult(document.DocumentFile.GetStream(), "application/pdf")
{
FileDownloadName = "Foo.pdf";
};
}
爲了您的信息:POCO =平原老CLR對象。不是普通的老C#對象:) – 2010-12-09 09:55:52
是的,我只是非常C#導向,直到我得到F#在我的腰帶。呵呵。 – 2010-12-09 10:09:12