Domanda

sto usando Cfwheels sviluppare un'applicazione in Coldfusion.

Ho un modello chiamato Vote.cfc. Prima che un oggetto di voto possa essere creato, aggiornato o eliminato, devo recuperare un oggetto post da un altro modello: Post.cfc. Un voto appartiene a un post. Un post ha molti voti.

Utilizzando i dati da post Oggetto, ho bisogno to validate the vote oggetto su più criteri e diverse funzioni. L'unico modo in cui riesco a pensare di persistere all'oggetto post in modo che sia disponibile per tali funzioni è memorizzarlo nell'ambito di richiesta.

Altri hanno detto che questa è una cattiva pratica. Ma non sono stato in grado di scoprire perché. Pensavo che l'ambito della richiesta fosse sicuro, e avrebbe senso usarlo in questa situazione.

L'altra mia alternativa è caricare una nuova istanza dell'oggetto post in ogni funzione che lo richiede. Sebbene le ruote utilizzino la memorizzazione nella cache, fare ciò ha causato i tempi di richiesta al picco del 250%.

AGGIORNARE

Ecco alcuni campioni. Innanzitutto, il controller gestisce che cerca di vedere se esiste già un oggetto di voto. In tal caso, lo elimina, se non lo fa, lo crea. La funzione del controller è essenzialmente una funzione di interruttore.

Controller Votes.CFC

   private void function toggleVote(required numeric postId, required numeric userId)
    {
    // First, we look for any existing vote
    like = model("voteLike").findOneByPostIdAndUserId(values="#arguments.postId#,#arguments.userId#");

    // If no vote exists we create one
    if (! IsObject(like))
    {
        like = model("voteLike").new(userId=arguments.userId, postId=arguments.postId);
    }
    else
    {
        like.delete()
    }           
}

Model VoteLike.cfc

Successivamente, un callback registrato nel modello spara prima della convalida. Chiama una funzione che recupera l'oggetto post a cui apparterrà il voto. La funzione getPost () memorizza il post nell'ambito della richiesta. Ora è reso disponibile per un mucchio di funzioni di convalida nel modello.

// Load post before Validation via callback in the Constructor
beforeValidation("getPost");

private function getPost()
{
    // this.postId will reference the post that the vote belongs to
    request.post = model("post").findByKey(this.postId);
}

// Validation function example
private void function validatesIsNotOwnVote()
{
    if (this.userId == request.post.userId)
    {
       // addError(message="You can't like your own post.");
    }
}

L'alternativa alla funzione getpost () è utilizzare una chiamata con ambito "this.post().userId"Per ottenere l'oggetto post, in quanto tale:

private void function validatesIsNotOwnVote()
{
    if (this.userId == this.post().userId)
    {
        addError(message="can't vote on your own post")
    }
}

Ma dovrei quindi ripetere questa chiamata con ambito this.post().userId Per ogni funzione, che è ciò che penso stia rallentando la richiesta!

È stato utile?

Soluzione

Aggiornamento con una nuova risposta in base al thread di commenti in OP

Dal momento che stai estendendo il modulo oggetto di voto di base VoteLike.CFC, i CFC condividono un ambito di variabili di thread-safe locale (purché non lo memorizzi nell'ambito di applicazione o server in cui può essere armeggiato da altri). Ciò significa che si imposta un valore, come variabili.post, una volta, e riferiscilo in qualsiasi funzione all'interno dello stack di CFCS.

Quindi cambia la tua funzione getpost () in questo:

beforeValidation("getPost");

private function getPost(){
    Variables.Post = model("post").findByKey(this.postID);
}

Ora, all'interno di qualsiasi funzione in entrambe le cose volati.cfc, è possibile fare riferimento a variabili.post. Ciò significa che hai una singola istanza di post nell'ambito delle variabili CFCS locali e non devi passarlo tramite argomenti o altri ambiti.

Risposta originale di seguito

Il modo "più corretto" per gestire questo sarebbe passare l'oggetto a ogni singola funzione come argomento. Che o aggiungi il post come proprietà dell'oggetto di voto, in modo che l'oggetto di voto abbia accesso all'oggetto post completo.

<cffunction name="doTheValidation">
    <cfargument name="ThePost" type="Post" required="true" />
    <cfargument name="TheVote" type="Vote" required="true" />
    <!--- do stuff here --->
</cffunction>

Il motivo per cui questa è una cattiva pratica è perché si richiede che i tuoi oggetti abbiano accesso a un campo di applicazione esterna, che può o meno esistere, al fine di svolgere il proprio lavoro. Se hai deciso di voler affrontare più voti o post su una singola pagina, devi armeggiare con l'ambito esterno per far funzionare le cose.

Stai molto meglio passare il tuo oggetto o usare la composizione per mettere insieme i tuoi oggetti in modo tale da essere a conoscenza.

Aggiornare

Per quanto riguarda i problemi delle prestazioni, se usi la composizione per legare i tuoi oggetti insieme, finisci con solo due oggetti in memoria, quindi non devi istanziare un mucchio di oggetti post inutili. Inoltre, trasmettere un CFC in una funzione come argomento passerà il CFC per riferimento, il che significa che non sta creando un duplicato del CFC in memoria, che dovrebbe anche occuparsi delle tue preoccupazioni sulle prestazioni.

Aggiornamento di esempio del codice

Per illustrare il commento "per riferimento" sopra, impostare i seguenti file e metterli in una sola directory da soli.

Testbject.cfc:

<cfcomponent output="false">
    <cfproperty name="FirstName" displayname="First Name" type="string" />
    <cfproperty name="LastName" displayname="Last Name" type="string" />

</cfcomponent>

indice.cfm:

<!--- Get an instance of the Object --->
<cfset MyObject = CreateObject("component", "TestObject") />

<!--- Set the initial object properties --->
<cfset MyObject.FirstName = "Dan" />
<cfset MyObject.LastName = "Short" />

<!--- Dump out the object properties before we run the function --->
<cfdump var="#MyObject#" label="Object before passing to function" />

<!--- Run a function, sending the object in as an argument, and change the object properties --->
<cfset ChangeName(MyObject) />

<!--- Dump out the object properites again, after we ran the function --->
<cfdump var="#MyObject#" label="Object after passing to function" />

<!--- Take a TestObject, and set the first name to Daniel --->
<cffunction name="ChangeName">
    <cfargument name="TheObject" type="TestObject" required="true" hint="" />
    <cfset Arguments.TheObject.FirstName = "Daniel" />
</cffunction>

Noterai quando esegui Index.cfm, che il primo dump ha il primo nome come Dan, mentre il secondo ha il primo nome come Daniel. Questo perché i CFC vengono passati alle funzioni per riferimento, il che significa che eventuali modifiche apportate all'interno di tale funzione vengono apportate all'oggetto originale in memoria. Quindi nessuna ricreazione di oggetti, quindi nessuna prestazione ha colpito.

Dan

Altri suggerimenti

request è un ambito globale, limitato alla richiesta di pagina (cioè thread sicuro), che vive per la durata della richiesta di pagina. Quindi è una cattiva pratica nello stesso modo in cui le variabili globali sono una cattiva pratica, ma di breve durata. Lo penso come vomitare i dati in aria o sopra la recinzione nella situazione che hai descritto, in cui qualsiasi altro codice può semplicemente strappare fuori aria.

Quindi per la tua situazione probabilmente va bene - aggiungi qualche riferimento utile al punto di consumo forse su dove i dati vengono inseriti nel request Ambito in primo luogo. Ciò afferma, se ogni volta stai tornando allo stesso metodo di origine, considera la memorizzazione nella cache all'interno di qualunque funzione sia responsabile creando quell'oggetto in esso (EG getVote()) E potresti usare l'ambito di richiesta per questo in quanto tale:

<cfparam name="request.voteCache" default="#structNew()#"/>
<cffunction name="getVote" output="false" access="public" returntype="any">
    <cfargument name="voteId" type="string" required="true"/>
    <cfif structKeyExists(request.voteCache, arguments.voteId)>
        <cfreturn request.voteCache[arguments.voteId]>
    </cfif>

    <!--- otherwise get the vote object --->
    <cfset request.voteCache[arguments.voteId] = vote>
    <cfreturn vote>
</cffunction>

Il rovescio della medaglia è se qualcos'altro cambia i dati durante la richiesta avrai una cache stantita, ma sembra che non ti aspetti cambiamenti durante l'esecuzione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top