в документации для Process.StandardOutput
говорится для чтения перед ожиданием иначе, можно зайти в тупик, отрывок, скопированный ниже:
// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "Write500Lines.exe";
p.Start();
// Do not wait for the child process to exit before
// reading to the end of its redirected stream.
// p.WaitForExit();
// Read the output stream first and then wait.
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Слишком много вопросов в одном, поэтому те, которые дают полные ответы на все, не подходят для формата ответов StackOverflow. Я постараюсь кратко описать подсказки, поэтому задайте для них отдельный вопрос, если этого недостаточно.
Самый популярный способ сделать это - назначить пользователя (и другую информацию) некоторым глобальный объект ( threading.local ()
в многопоточном приложении). Это очень плохой способ, который затрудняет обнаружение ошибок.
Лучший способ - назначить пользователя для сеанса. Это нормально, когда сеанс создается для каждого веб-запроса (на самом деле, это лучший вариант для приложения с аутентификацией в любом случае), поскольку этот сеанс использует единственный пользователь. Но передать описание таким образом не так хорошо.
И мое любимое решение - это продвижение Session. commit ()
, чтобы принять необязательный параметр пользователя (и, возможно, другую информацию) и назначить ему текущую транзакцию. Это наиболее гибкий вариант, и он хорошо подходит для передачи описания. Обратите внимание, что информация привязана к отдельной транзакции и передается очевидным образом при закрытии транзакции.
Существует sqlalchemy.org.attributes.instance_state (obj)
, содержащий всю информацию, которую вы необходимость. Наиболее полезным для вас, вероятно, является словарь state.committed_state
, который содержит исходное состояние для измененных полей (включая отношения «многие ко многим!»). Существует также метод state.get_history ()
(или sqlalchemy.org.attributes. get_history ()
функция), возвращающая объект истории с помощью метода has_changes ()
и добавленных свойств
и удаленных
для нового и старого значения соответственно. В более позднем случае используйте state.manager.keys ()
(или state.manager.attributes
), чтобы получить список всех полей.
SQLAlchemy поддерживает расширение mapper, которое может предоставлять перехватчики до и после обновления, вставки и удаления. Вам необходимо предоставить собственное расширение со всеми хуками до (вы не можете использовать after, поскольку состояние объектов изменяется при сбросе). Для декларативного расширения легко написать подкласс DeclarativeMeta
, который добавляет расширение сопоставителя для всех ваших моделей. Обратите внимание, что вам нужно дважды сбросить изменения, если вы используете сопоставленные объекты для журнала,
У нас есть довольно подробный рецепт "управления версиями" на http://www.sqlalchemy.org/trac/wiki/UsageRecipes/LogVersions . Похоже, что некоторые другие пользователи внесли в него несколько вариантов. Механика «добавить строку, когда что-то изменяется на уровне ORM» присутствует.
В качестве альтернативы вы также можете перехватить на уровне выполнения, используя ConnectionProxy
, поискать в документации SQLA, как это использовать .
edit: управление версиями теперь является примером, включенным в SQLA: http://docs.sqlalchemy.org/en/rel_0_8/orm/examples.html#versioned-objects