2012-05-23 1 views
1

Просто хотелось бы узнать, можно ли выполнить ленивую загрузку без linq или ORM. Есть несколько запросов, которые мне нужно сделать, что не подходит для ORM. Мне также нужно будет передать запрос между методами. Кроме того, я не мог найти никаких микросов для достижения этого. Есть какой-либо способ сделать это?Как сделать ленивую загрузку с помощью специальных запросов sql: SQL-фильтрация

var q = "Select Name from Test1" 

Теперь мы должны добавить OR или AND или IN или что-то еще

Этот запрос будет передан в различных методов фильтрации. Есть ли способ сделать это с помощью микро ORM или AD Hoc SQL-запросов?

+0

Вы передаете запрос sql или командный класс между методами? Это поможет, если вы сможете дать больше информации о том, что вы пытаетесь сделать. Вы выполняете запрос, но можете ждать, чтобы обработать результаты? –

+0

То, что Linq может быть закодировано вручную (например, [Edulinq] (http://msmvps.com/blogs/jon_skeet/archive/tags/Edulinq/default.aspx)). Что не так с тем, как работает Linq? – Brian

ответ

1

Один из подходов заключается в том, чтобы выразить запрос как своего рода объект в памяти, который вы можете добавить к нему. Например, при использовании некоторых составляют иерархию объектов:

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. Когда вы начинаете думать о присоединениях (довольно тривиально для поддержки), подзапросы (неприятные), рекурсивные табличные выражения (ouch) все усложняются. Просто просмотрите этот сайт и посмотрите, как могут возникать сложные SQL-запросы, и представьте, что вы можете выполнить синтаксический анализ для , который.

Многие из проектов, которые я видел, пытались представить запросы как некоторую промежуточную форму, например. структуру (список полей, имя таблицы, список условий WHERE, список предложений ORDER BY и т. д.), а затем добавить новые записи в это представление списка (добавьте новую запись в список WHERE, чтобы добавить новый фильтр). Но, ретроспективно, эти представления бледнеют по сравнению с тем, что предлагает LINQ. Я признаю, что LINQ - это предложение «все или ничего», и вы либо сами commit, либо нет. Но попытка заново изобрести его только раскрывает сложность проблемы. Сегодня я бы подошел к проблеме с другой стороны: начните с LINQ и попытайтесь удержать ее в страхе, не позволяйте ей превращаться в отвратительного монстра неконтролируемого инструмента генерации запросов, в котором каждый слой проекта добавляет некоторый фильтр в IQueryable а затем бомбить сервер с помощью того, что оптимизатор не может даже распутать.

PS. Why I Wrote AREL - хороший обзор по всей этой проблеме.

+0

Спасибо, я буду использовать Linq. Я попробовал решение Джеймса Блэка, но мой проект стал очень быстрым. Linq - лучший выбор – Luke101

6

Почему бы просто не использовать Func или Action и задать ему свой запрос, поэтому, передавая его следующей функции, он может быть выполнен, когда это необходимо.

Это будет работать как ленивая загрузка.

+0

см. Мой ответ за то, как вы могли это сделать, используя 'Lazy ' class –

+0

@JoshE. Проблема в том, что я попросил разъяснить, что пытается сделать OP, и без этого трудно найти хороший пример того, как это можно сделать с помощью Lazy, Func или Action. –

+0

точно! Я просто хотел продемонстрировать, что они являются функциональными эквивалентами. Было бы неплохо, если бы OP предоставил больше информации - «... неподходящее для ORM» является неопределенным, так как необходимо «передавать запрос между методами». Интересно, может ли ответ быть таким простым, как «hey use' IQueryable »:) –

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 секунд без какой-либо активности.

+0

Я ненавижу защищать свой собственный пост. Но для ответа на ваш комментарий о достоверных и официальных источниках из самой документации MSDN «DataReader предоставляет небуферизованный поток данных, который позволяет процедурной логике последовательно обрабатывать результаты из источника данных. DataReader - хороший выбор при извлечении больших сумм данных, поскольку данные не кэшируются в памяти ». Любой ORM, который вы обнаружите, скорее всего, будет использовать DataReader напрямую, поскольку он является официальным API Microsoft для подключения к SQL Server. В моем примере показано, как вы можете обернуть его для удобства. – Wulfram

5

Вы можете использовать

< Ленивый T>

для этого. Он полагается на Func, как предлагает Джеймс, но также поддерживает кеширование и безопасность потоков.

http://msdn.microsoft.com/en-us/magazine/ff898407.aspx

EDIT: Поскольку вы теперь ищете дополнительные возможности ORMs, такие как фильтрация и сортировку, но с гибкостью, чтобы написать сырой SQL, я рекомендую вам посмотреть в ОРМ, такие как Entity Framework или Nhibernate и использовать некоторые из своих сырых sql-функций, где это необходимо, например

session.CreateSQLQuery (sql);

ORM также позволяет вам более строго печатать, чтобы устранить ошибки при динамическом добавлении фильтров.

1

Класс Lazy<T> звучит так, как будто вы ищете. Как подсказывает Кайдо и Джеймс, вам нужно определить метод, который будет выполнять фактическую загрузку, а затем передать его в 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 для получения дополнительной информации

1

Возможно, вы захотите рассмотреть Repository pattern в своем дизайне. Репозиторий решает, как предоставить вещи классу клиента. Как это делается, не имеет значения для потребителя, и его можно передавать или вводить там, где это необходимо.

Также рассмотрите кеш объекта, например Redis или Memcached. Они особенно полезны, если вам нужны объекты «ленивой загрузки» не последовательно. Сложные SQL-запросы могут быть сделаны для возврата только первичных ключей вместо десятков больших полей данных. Сохраните все ключи для вашего запроса, а затем создайте бизнес-объекты по требованию.

Если вы когда-либо перерастаете свою реализацию, репозиторий позволяет легко улучшить, не затрагивая классы, использующие его.

Смежные вопросы