我正在开始一个新的应用程序。我运行查询到数据库然后我返回一个海关对象列表。这是一个例子:
使用此方法,我可以获得表格的所有记录。示例:SELECT ID,NAME,LASTNAME FROM PKR_PLAYER
public List<TEntity> GetAll()
{
List<TEntity> all = new List<TEntity>();
String query = String.Format("SELECT {0} FROM {1}",AllFieldsSelection,TableName);
var data = SqlExecutionData.Create().WithConn(ConnectionString).WithQuery(query);
foreach (IDataRecord record in SqlServerUtils.GetRecords(data))
{
all.Add(CreateOneFromRecord(record));
}
return all;
}
通过这个我创建一个TEntityObject,其数据存储在记录
中private TEntity CreateOneFromRecord(IDataRecord record)
{
var result = new TEntity();
for (int i = 0; i < record.FieldCount; i++)
{
ColumnMap colMap = maps.FirstOrDefault(x => x.Column.Equals(record.GetName(i)));
if (colMap == null || record.IsDBNull(i)) continue;
object value = record.GetValue(i);
colMap.PropertyInfo.SetValue(result, value, null);
}
return result;
}
我如何执行查询
public static IEnumerable<IDataRecord> GetRecords(SqlExecutionData data)
{
using (SqlConnection sqlConnection = new SqlConnection(data.ConnectionString))
using (SqlCommand command = new SqlCommand(data.Query, sqlConnection))
{
if (data.Parameters!=null && data.Parameters.Count > 0)
{
foreach (String key in data.Parameters.Keys)
command.Parameters.AddWithValue(key, data.Parameters[key]);
}
sqlConnection.Open();
using (IDataReader rdr = command.ExecuteReader())
{
while (rdr.Read())
{
yield return (IDataRecord)rdr;
}
}
sqlConnection.Close();
}
}
简而言之,我们的想法是迭代一个SqlDataReader(带有yield return)并创建一个实体,最后将它存储在List上。
我认为这会耗费大量资源。该查询返回aprox 22k记录,并且将经常调用GetAll方法。有时会每隔1或2分钟调用一次GetAll方法。
我只执行了几次(10次aprox)GetAll方法,Windows任务管理器上的信息显示内存在几秒钟内从17MB增长到45 MB。
我相信这段代码不是表现。
问题是:如何让代码消耗更少的内存?可能是我必须更改列表,但有什么替代方案?
答案 0 :(得分:2)
你可以使用yield return
但是你需要稍微改变你的方法
这样可以最大限度地减少内存消耗。
public IEnumerable<TEntity> GetAll()
{
String query = String.Format("SELECT {0} FROM {1}",AllFieldsSelection,TableName);
var data = SqlExecutionData.Create().WithConn(ConnectionString).WithQuery(query);
foreach (IDataRecord record in SqlServerUtils.GetRecords(data))
{
yield return CreateOneFromRecord(record);
}
}
这将消耗更少的内存,但它也将保持与SQL Server的连接打开。 请在this MSDN article上阅读更多内容。
答案 1 :(得分:1)
另一个选择可能是委托每个项目。 这更明确,您可以更好地控制每个项目。 但是你需要小心,委托调用将阻止迭代。 我更喜欢使用IEnumerable,因为它在.NET中有很多功能(PLinq,foreach,Collection-ctors)。
public void IterateItems(Action<int, TEntity> handler)
{
String query = String.Format("SELECT {0} FROM {1}",AllFieldsSelection,TableName);
var data = SqlExecutionData.Create().WithConn(ConnectionString).WithQuery(query);
var index = 0;
foreach (IDataRecord record in SqlServerUtils.GetRecords(data))
{
handler(CreateOneFromRecord(index, record));
index++;
}
}
内存有效的通话:
public void MemoryEfficient()
{
ProcessItems((index, item) => Console.WriteLine("{0}: {1}", index, item));
}
收集列表中的项目:
public void FillAList()
{
var list = new List<TEntity>();
ProcessItems((index, item) => list.Add(item));
}