如何使用即席SQL查询进行延迟加载:SQL过滤
本文关键字:SQL 延迟加载 过滤 查询 何使用 | 更新日期: 2023-09-27 18:35:05
只是想知道是否可以在没有linq或ORM的情况下进行延迟加载。我需要做一些不适合 ORM 的查询。我还需要在方法之间传递查询。另外,我找不到任何微型orms来实现这一点。有什么办法可以做到这一点吗?
var q = "Select Name from Test1"
现在我们必须添加一个 OR 或 AND 或 IN 或其他东西
此查询将传递给要筛选的不同方法。有没有办法使用微型ORM或AD Hoc SQL查询来做到这一点?
您可以直接使用数据读取器,也可以通过懒惰地评估它的类来执行此操作。参见 http://msdn.microsoft.com/en-us/library/haa3afyz(v=vs.100).aspx
举个粗略的例子,你可以做这样的事情
public class LazyReader {
SqlDataReader m_reader;
SqlCommand m_command;
SqlConnection m_connection;
public LazyReader(SqlConnection connection, String sql)
{
m_command = new SqlCommand(sql, connection);
m_connection = connection;
}
public IEnumerable<Object[]> read()
{
using (m_connection) {
m_connection.Open();
m_reader = command.ExecuteReader();
while (m_reader.HasRows)
{
while (m_reader.Read())
{
Object[] values = new Object[m_reader.FieldCount];
m_reader.GetValues(values);
yield return values;
}
m_reader.NextResult();
}
m_reader.Close();
}
}
}
您可能需要对示例进行一些摆弄,但想法是使用 DataReader 并逐个读取行,通过 IEnumerable 传递结果和收益返回,这将导致惰性计算。然后,您可以传递IEnumerable并随心所欲地阅读。请注意确保阅读一致,否则 SQLConnection 将在 30 秒后终止,没有任何活动。
为什么不直接使用 Func
或 Action
并让它定义你的查询,这样当你把它传递给下一个函数时,它可以在需要时执行。
它的功能就像延迟加载一样。
懒惰
为此。正如James所建议的那样,它依赖于Func,但也支持缓存和线程安全。
http://msdn.microsoft.com/en-us/magazine/ff898407.aspx
编辑:由于您现在正在寻找ORM的其他功能,例如过滤和排序,但是可以灵活地编写原始sql,因此我建议您研究ORM,例如Entity Framework或Nhibernate,并在适当的情况下使用其一些原始SQL功能,例如
会期。CreateSQLQuery(sql);
ORM 还允许您更强的键入功能,以消除动态添加位置过滤器时的错误。
一种方法是将查询表示为某种内存中的对象,您可以进一步向其添加表达式。例如,使用一些由组成的对象层次结构:
var q = Table("Test1").Select("Name");
您可以通过添加筛选器来进一步细化它:
q = q.Where("ID= 1");
但这当然意味着您正在重新发明IQueryable
.然后最好只接受 LINQ 并选择提供程序(LINQ2SQL 或 LINQ2EF 等)。
另一种方法是保留字符串即席表示形式:
var q = "Select Name from Test1";
但是,如何添加过滤器呢?您必须解析字符串并插入 WHERE 子句。这绝非微不足道。您很快就会实现一个成熟的SQL解析器(lex + yacc或bison+flex)和抽象语法树,然后将其序列化为新的SQL字符串。一旦你开始考虑连接(支持起来相当微不足道),子查询(讨厌),递归表表达式(哎哟),事情就会变得更加复杂。只需浏览这个网站,看看SQL查询是如何复杂的,并想象为此实现一个解析。
我见过的许多项目都试图将查询表示为某种中间形式,例如结构(字段列表、表名、WHERE 条件列表、ORDER BY 子句列表等),然后在这些列表表示形式中添加新条目(在 WHERE 列表中添加新条目以添加新过滤器)。但是,回想起来,与 LINQ 提供的功能相比,这些表示形式相形见绌。我承认,LINQ 是一个全有或全无的产品,你要么自己承诺,要么不承诺。但试图重新发明它只会揭示问题的复杂性。今天,我将从另一端处理这个问题:从 LINQ 开始并尝试阻止它,不要让它成长为一个可怕的无法控制的查询生成工具的怪物,其中项目的每一层都向IQueryable
添加一些过滤器,然后用任何优化器甚至无法解开的东西轰炸服务器。
附言。我为什么写AREL是关于整个问题的好读物。
Lazy<T>
类听起来像你要找的。正如 Kaido 和 James 所建议的那样,您需要定义一个将执行实际加载的方法,然后将其传递给延迟加载(实际上是初始化)对象的 ctor。
前任:
public class SomeClass
{
Lazy<List<string>> myLazy = new Lazy<List<string>>(LoadData);
private List<string> LoadData()
{
//open connection, execute your query, read/project data into a List, etc
return new List<string> { "Hello", "My", "Name", "Is", "Earl" };
}
}
Lazy<T>
类的行为完全符合您的预期 - 它会延迟所包含对象的初始化,直到通过 Value
属性引用它。有关详细信息,请参阅 MDSN 参考
您可能需要在设计中考虑存储库模式。 存储库决定如何向客户端类提供内容。 如何完成对消费者来说并不重要,它可以在需要的地方传递或注入。
还要考虑对象缓存,例如 Redis 或 Memcached。 如果您需要非顺序"延迟加载"对象,则这些特别有用。 可以进行复杂的SQL查询,只返回主键,而不是几十个大数据字段。 存储查询的所有键,然后按需创建业务对象。
如果你的实现已经超出了你的实现范围,Repository 可以很容易地改进,而不会影响使用它的类。