想知道是否可以在没有linq或ORM的情况下进行延迟加载。我需要做一些不适合ORM的查询。我还需要在方法之间传递查询。此外,我找不到任何微观的动作来实现这一目标。有没有办法做到这一点?
var q = "Select Name from Test1"
现在我们必须添加OR或AND或IN或其他
此查询将传递给要过滤的不同方法。有没有办法使用微型ORM或AD Hoc SQL查询来做到这一点?
答案 0 :(得分:7)
您可以直接使用datareader,也可以通过一个懒惰地评估它的类来完成。见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秒后终止而没有任何活动。
答案 1 :(得分:6)
为什么不使用Func
或Action
并让它定义您的查询,所以当您将其传递给下一个函数时,它可以在需要时执行。
它的功能就像延迟加载一样。
答案 2 :(得分:5)
您可以使用
懒惰&lt; T&gt;
为此。它依赖于James建议的Func,但也支持缓存和线程安全。
http://msdn.microsoft.com/en-us/magazine/ff898407.aspx
编辑:由于您现在正在寻找ORM的其他功能,例如过滤和排序,但是可以灵活地编写原始sql,我建议您查看ORM,例如Entity Framework或Nhibernate并使用它们的一些适当的原始sql功能,如执行Session.createSQLQuery(SQL);
ORM还允许您更强大的输入,以便在动态添加过滤器时消除错误。
答案 3 :(得分:1)
Lazy<T>
课程听起来像你正在寻找的。正如Kaido和James建议的那样,你需要定义一个执行实际加载的方法,然后将它传递给你的懒惰(真正初始化)对象的ctor。
EX:
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
属性引用它。有关详细信息,请参阅the MDSN reference
答案 4 :(得分:1)
您可能需要在设计中考虑Repository pattern。存储库决定如何向客户端类提供内容。如何完成对消费者来说无关紧要,可以在需要时传递或注入。
还要考虑Redis或Memcached等对象缓存。如果您需要非连续地“延迟加载”对象,这些特别有用。可以使复杂的SQL查询仅返回主键而不是数十个大数据字段。存储查询的所有密钥,然后根据需要创建业务对象。
如果你的实现已经不再适用,那么Repository可以很容易地改进,而不会影响使用它的类。
答案 5 :(得分:1)
一种方法是将查询表达为某种内存中对象,您可以进一步向其中添加表达式。例如,使用一些组成的对象层次结构:
var q = Table("Test1").Select("Name");
您可以通过添加过滤器进一步完善此功能:
q = q.Where("ID= 1");
但当然这意味着你正在重新发明IQueryable
。你最好接受LINQ然后选择一个提供程序(LINQ2SQL或LINQ2EF等)。
另一种方法是保持字符串ad-hoc表示:
var q = "Select Name from Test1";
但是你如何添加过滤器?您必须解析字符串并插入WHERE子句。这远非微不足道。您很快就会实现一个完全成熟的SQL解析器(lex + yacc或bison + flex)和一个抽象语法树,然后将其序列化为一个新的SQL字符串。一旦你开始考虑连接(相当简单的支持),子查询(讨厌),递归表表达式(哎哟)事情会变得越来越复杂。只需浏览这个网站,看看复杂的SQL查询可以获得多少,并想象实现 的解析。
我见过的许多项目试图将查询表示为某种中间形式,例如。一个结构(字段列表,表名,WHERE条件列表,ORDER BY子句列表等)然后在这些列表表示中添加新条目(在WHERE列表中添加一个新条目以添加新过滤器)。但是,回想起来,与LINQ提供的相比,这些表现形式相形见绌。我承认,LINQ是一个全有或全无的产品,您自己是commit。但试图重新发明它只能揭示问题的复杂性。今天我将从另一端接近问题:从LINQ开始并试图阻止它,不要让它成长为一个无法控制的查询生成工具的可怕怪物,其中项目的每一层都为{添加一些过滤器{1}}然后用优化器甚至无法解开的东西轰炸服务器。
PS。 Why I Wrote AREL是对这整个问题的一个很好的解读。