1

我正在尝试重构我的所有 CFC 以避免使用 SESSION 和 APPLICATION 变量(这不是一件容易的事)。

然而,在这个应用程序中,每个数据库调用都使用 SESSION 变量,因为不同的登录用户可能正在访问不同的数据库和模式:

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

我不想麻烦将这两个 SESSION 变量传递给每个访问数据库的方法调用。尤其是这种情况,因为我不想在远程 AJAX 调用中传递 DSN 和模式名称。

这样做的最佳实践是什么 - 对于所有不应在 CFC 中使用的范围?

4

5 回答 5

2

我认为由于数据源确实是可变的,我会将其作为可选参数传递给每个函数,并将默认值设置为变量作用域的 dsn 属性。我会在 CFC 的构造函数中设置范围为 DSN 的变量。这样,您只需为 AJAX 调用传入 DSN。

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

我会使用您的应用程序的会话范围来存储用户 dsn 名称并使用该 var 传递给 AJAX 调用。

于 2011-07-13T16:02:36.293 回答
2

您应该创建一个“init”方法,作为 CFC 的构造函数。然后,您可以实例化 CFC 并将它们存储在共享范围内,最有可能是应用程序范围。从这里开始,为了通过 AJAX 使用这个 CFC,我通常会创建一个远程外观。基本上,这是另一个将直接访问应用程序范围内的 CFC 实例的 CFC。它将实现您需要通过 Ajax 访问的方法,通过access="remote"让您的应用程序访问access="public"来自实际 CFC 的方法来公开它们。在这种情况下,作为设计模式的一部分,通常认为远程外观可以直接访问应用程序范围。

一个简单的例子:

示例.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") />

远程.cfc:

<cfcomponent output="false">
    <cffunction name="doStuff" access="remote" returntype="query">
        <cfreturn application.example.doStuff() />
    </cffunction>
</cfcomponent>
于 2011-07-13T16:24:44.923 回答
1

您可以在 Application.cfc 的 onRequest 或 onRequestStart 函数中设置数据源变量吗

<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

于 2011-07-13T16:00:40.700 回答
1

您选择的范围(对于此问题的任何变体,而不仅仅是 DSN)应基于值的生命周期是否与范围的生命周期相同。

在我们的应用程序中,DSN 仅在应用程序的生命周期中设置一次,因此我们在 onApplicationStart 中创建了一个 application.config 结构(从文件中解析),其中是 application.config.dsn

如果您的值在会话之间确实发生了变化,但在会话的整个生命周期内没有发生变化,请继续使用会话范围。

如果您的值可以针对任何给定请求更改,但不在请求中间,请将其放在请求范围内。

也就是说,仍然听从 ryan 的建议并添加仅默认为该值的可选参数:灵活总是最好的。

于 2011-07-13T16:19:39.503 回答
0

我对此的建议是创建一个基类,然后让需要数据库访问的组件扩展该组件。它不必在直接的父层次结构中,而是在某个地方。

他们的目标是做两件事,将 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

说得通?

于 2011-07-13T16:19:46.277 回答