Как можно избежать использования переменных SESSION в CFC, когда они используются для схем источника данных и базы данных? - PullRequest
1 голос
/ 13 июля 2011

Я пытаюсь реорганизовать все свои CFC, чтобы избежать использования переменных SESSION и APPLICATION (задача не из легких).

Однако в этом приложении переменные SESSION используются при каждом вызове базы данных, поскольку разные вошедшие в систему пользователи могут обращаться к разным базам данных и схемам:

<cfquery name="qEmployees" datasource="#SESSION.DataSourceName#">
    SELECT *
    FROM #SESSION.DatabaseSchema#.Employees
</cfquery>

Я не хочу проходить через проблему передачи этих двух переменных SESSION в каждый вызов метода, который обращается к базе данных. Это особенно верно, поскольку я не хочу передавать DSN и имена схем в удаленных вызовах AJAX.

Каков наилучший способ сделать это - для всех областей, которые не должны использоваться в ХФУ?

Ответы [ 5 ]

2 голосов
/ 13 июля 2011

Вы должны создать метод "init", который будет служить конструктором для вашего CFC.Затем вы можете создать экземпляры CFC и сохранить их в общей области, скорее всего, в области приложения.Отсюда, чтобы использовать этот CFC через AJAX, я обычно создаю удаленный фасад.По сути, это еще один CFC, который будет напрямую обращаться к экземпляру CFC в области приложения.Он будет реализовывать методы, к которым вам нужно получить доступ через Ajax, предоставлять их с помощью access="remote", предоставляя вашему приложению доступ к access="public" методам из фактического CFC.В этом случае общепринято, что удаленный фасад может получить доступ к области приложения непосредственно как часть шаблона проектирования.

Простой пример:

example.cfc:

<cfcomponent output="false">
    <cffunction name="init" access="public" output="false" returntype="any">
        <cfargument name="dsn" type="string" required="true" />
        <cfset variables.dsn = arguments.dsn />
        <cfreturn this />
    </cffunction>
    <cffunction name="doStuff" access="public" output="false" returntype="query">
        <cfset var q = "" />
        <cfquery name="q" datasource="#variables.dsn#">
        select stuff from tblStuff
        </cfquery>
        <cfreturn q />
    </cffunction>
</cfcomponent>

В вашем Application.cfc метод onApplicationStart ():

<cfset application.example = createObject("component","example").init(dsn = "somedsn") />

remote.cfc:

<cfcomponent output="false">
    <cffunction name="doStuff" access="remote" returntype="query">
        <cfreturn application.example.doStuff() />
    </cffunction>
</cfcomponent>
2 голосов
/ 13 июля 2011

Я думаю, что поскольку источник данных действительно является переменным, я передал бы его в каждую функцию в качестве необязательного параметра и установил бы значение по умолчанию для атрибута dsn области действия переменных.Я бы установил переменную DSN в конструкторе CFC.Таким образом, вам нужно только передать DSN для вызовов AJAX.

<cffunction name="doFoo" access="remote"...>
    <cfargument name="dsn" type="String" required="false" default="#variables.datasource#" />
</cffunction>

Я бы использовал область сеанса вашего приложения для хранения имени пользователя dsn и использовал эту переменную для передачи вызова AJAX.

1 голос
/ 13 июля 2011

Область действия, которую вы выбираете (для любого варианта этого вопроса, а не только для уведомлений о доставке), должна основываться на том, совпадает ли время жизни значения со временем существования области.

В нашем приложенииDSN устанавливается только один раз за время существования приложения, поэтому у нас есть структура application.config, которая создается (анализируется из файла) в onApplicationStart, и внутри нее есть application.config.dsn

Если вашзначение действительно изменяется между сессиями, но не в течение жизни сеанса, продолжайте и используйте область действия сеанса.

Если ваше значение может измениться для любого данного запроса, но не в середине запроса, введитеэто в объеме запроса.

Тем не менее, все равно прислушайтесь к совету Райана и добавьте необязательные аргументы, которые только по умолчанию соответствуют этому значению: гибкость всегда является лучшей.

1 голос
/ 13 июля 2011

Можете ли вы установить переменные источника данных в функциях onRequest или onRequestStart в вашем Application.cfc

<cffunction name="onSessionStart">
    <cfset session.dsn = _users_personal_dsn_ />
</cffunction>


<cffunction name="onRequestStart" >
   <cfset dsn = "#session.dsn#" />
</cffunction>

<cfquery name="qEmployees" datasource="#dsn#">
    SELECT *
    FROM #SESSION.DatabaseSchema#.Employees
</cfquery>

и т. Д.

не уверен, что это сработает [не проверено - на самом деле чувствует себя немного небрежно] -sean

0 голосов
/ 13 июля 2011

Мое предложение для этого - создать базовый класс, а затем сделать так, чтобы ваши компоненты, которым требуется доступ к базе данных, расширили этот компонент.Это не обязательно должно быть в непосредственной родительской иерархии, но где-то внизу.

Их цель состоит в том, чтобы сделать две вещи, сохранить абстрагирование cfc от основной программы и сделать его легко настраиваемым.Это выполняет оба.

Таким образом, ваш CFC, который запрашивает базу данных, будет выглядеть примерно так:

<cfcomponent extends="DataAccessBase">
<cffunction name="myFunction" access="public" returntype="string">
    <cfquery datasource="#getDSN()#" name="qStuff">select * from table</cfquery>
</cffunction>

Ключ выше - это часть extends="DataAccessBase".Это добавляет уровень абстракции, где вы можете контролировать доступ к данным в одной настраиваемой точке, но он не привязан к самому приложению, оставляя компонент абстрагированным от места его реализации.

Ваш DataAccessBase.cfc может выглядеть примерно такэто:

<cfcomponent>
<cffunction name="loadSettings">
    <cfparam name="request.settings" default="#structNew()#">
    <cfparam name="request.settigns.loaded" default="false">
    <cfif request.settings.loaded eq false>
        <!--- load settings from resource bundle etc --->
        <cfset request.settings.dsn     = 'myDSN'>
        <cfset request.settings.loaded  = true>
    </cfif>
</cffunction>
<cffunction name="getDsn" access="public" returntype="string">
    <cfset loadSettings()>
    <cfreturn request.settings.dsn>
</cffunction>

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

Я не вижу причин передавать DSN при каждом вызове метода.Да, это работает, но это не обязательно.Компоненты разработаны со встроенным допущением структуры данных, так что вы знаете, что он не собирается переходить от вызова addItem () к вызову updateItem (), таким образом, его дублирование работы, что означает дополнительные точки отказа.: P

Имеет смысл?

...