这是场景:如何使用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