Where to put queries (especially long ones) in a CFWheels project - view

(wheels novice here)
I'm trying to figure out the best place to put a number of large and/or complex queries that are used in the controllers function for the view.
I have a view calendar.cfm, and a controller with the function:
<cffunction name="calendar">
<cfset formData = getValidatedFormData()>
<cfset fromDate = formData.fromDate>
<cfset toDate = formData.toDate>
<cfset dbLocation = formData.dbLocation>
<cfset dateList = getDateList()>
<cfset selectLists = getSelectLists()>
<cfset companySelectList = selectLists.companySelectList>
<cfset activitySelectList = selectLists.activitySelectList>
<cfset instructorSelectList = selectLists.instructorSelectList>
<cfset statusSelectList = selectLists.statusSelectList>
<cfset courseNumberLists = getCourseNumberLists()>
<cfset girsCourseNumberList = courseNumberLists.girsCourseNumberList>
<cfset activityCourseNumberList = courseNumberLists.activityCourseNumberList>
<cfset activityCourseNumberList = courseNumberLists>
<cfset ELMActivityList = getELMActivityList()>
<cfset activityList = getActivityList()>
<cfif len(elmActivityList.LM_ACT_CD) gt 0>
<cfset elmActIDList = Replace(QuotedValueList(ELMActivityList.LM_ACT_CD, ","), "'',", "", "all")>
<cfelse>
<cfset elmActIDList = "'String1','String2'">
</cfif>
<cfif len(activityList.girs_act_cd) gt 0>
<cfset girsActIDList = Replace(QuotedValueList(activityList.GIRS_ACT_CD, ","), "'',", "", "all")>
<cfelse>
<cfset girsActIDList = "'String1','String2'">
</cfif>
<cfset combinedList = getCombinedList( elmActIDLIst , girsActIDList )>
<cfset needUnion = false>
<cfset programList = getProgramList()>
</cffunction>
Each of the functions, such as getDateList(), contains long and/or complex queries. The controller is already almost 700 lines long, and I've only implemented one of the 5 or 6 views in the project -- which will require additional queries.
I have the sense that I'm doing this wrong. I tried putting all the query functions in a cfc file in the models folder
<cfcomponent extends="Model">
functions...
but I can't figure out how to call them from the calendar function in the controller. I tried, for instance,
<cfset dateList= model("model_file_name").getDateList()>
but that isn't it.
Where should I put the queries and how should I call them?
EDIT
When I try to call the function in the model, I get "The data source could not be reached." However, I explicitly specify the datasource in the query. For example I have the following function in both the model and controller:
<cffunction name="getDateList" returntype="any">
<cfquery name="dateList" dataSource="ELM_Prod">
SELECT DATES FROM
(SELECT dateadd(dd,DAYS, <cfqueryparam cfsqltype="cf_sql_date" value="#fromDate#">) DATES
FROM
(SELECT TOP 365 colorder - 1 AS DAYS from master..syscolumns
WHERE id = -519536829 order by colorder) a
WHERE datediff(
dd,
dateadd(
dd, DAYS, <cfqueryparam cfsqltype="cf_sql_date" value="#fromDate#">
),
<cfqueryparam cfsqltype="cf_sql_date" value="#toDate#">
) >= 0
AND dateadd(
dd,
DAYS,
<cfqueryparam cfsqltype="cf_sql_date" value="#fromDate#">
) <= <cfqueryparam cfsqltype="cf_sql_date" value="#toDate#">
) a order by DATES
</cfquery>
<cfreturn dateList>
</cffunction>
When I call the function in the controller with <cfset dateList = getDateList()>, everything is fine, and I don't get the datasource error. However if I call it from the model with <cfset dateList = model("wheels_girs_model").getDateList()/>, I get the error. Because I am using more than one datasource, I'm not setting the datasources in the config file. I have set them both up in the admin panel and refer to them directly in the cfqeury. What would prevent the model from finding the datasource?

There are different ways to do this:
First of all, 700 lines per controller is not too long.
You can put all queries in the controller it self. You can create different functions for different queries (i guess you are doing this).
If you still think this is too long. You can group functions in different cfc's. Then you can create object of these cfc's using createObject to access methods or you can invoke cfc using cfinvoke to access your function.
Secondly, You can put your queries in the model file. You need to create a function in the your model cfc, then add your query in this function and you need to return the query or particular value, whatever you want using cfreturn.
You can call that function using the format
<cfset yourVariableName = model("yourModelName").yourCustomFunctionName(arguments if required) />
After adding a new function to your cfc, you need to reload application using your_site_url/?reload=true&password=password_you_set
Third, as Dan Bracuk suggested, you can use stored procedures and call stored procedures using cfstoredProc
Edit Answer to the problem i understood from comment
You should have put error in the question itself as this changes everything. This error has nothing to do with your code. This error means you haven't set the correct datasource or you haven't created datasource but you are using it or it means there is something wrong in your datasource configuration.
Do as the following:
Check whether you have defined correct datasource in the
config/settings.cfm.
If not, please define it. You can define the datasource by <cfset
set(dataSourceName="your_desired_datasource_name.") />
If yes, then go to your cfadministrator control and datasource tab.
Check whether that datasource exists or not.
If not, create datasource. If yes, check whether it is correctly
configured or not, also check for spelling differnece between the
datasource name from cfadministrator and the one defined in the
config/settings.cfm.
Your problem should go if you do one of the above. Remember, whatever you do, you have to reload application using yourappurl/?reload=1&password=password_you_set
Second Edit:
Your question still doesn't give us clear info like How do you set datasource in admin panel and then how do you access in the query? This should have been different question as this question is totally different from the original question. Anyway, You should always use default datasource (the one defined in the config/settings.cfm). You can override this datasource in the model cfc. You can override default datasource for particular model by <cfset dataSource("your datasource name for that particular table")>. Please check the link for more info. And if you have more queries, you should as separate question (you will probably get more responses).

Related

Coldfusion and session variable not setting

I have a survey form with 5 ques, there is one question on each page and user clicks through them with next button on the page. Now, the user is not logged in, I want to set a session variable only when the user takes the first ques on form and clicks next. But I am getting userid not defined in session for the line 2. I am not really sure what I am doing wrong here. Can anyone suggest if they see what is going on. I don't want to be creating multiple userids every time he hits next button. Thanks
<cfif structKeyExists(FORM, "user_mode") and form.user_mode EQ "next">
<cfif NOT ( StructKeyExists(session,userid) )>
<cfquery name="insertuser" datasource="#application.datasource#">
INSERT INTO survey_user(ip_address)
VALUES (<cfqueryparam cfsqltype="cf_sql_varchar" value="#CGI.REMOTE_ADDR#" />)
</cfquery>
</cfif>
</cfif>
StructKeyExists(session,userid)
should be:
structKeyExists( session, 'userid' )
Note the quotes. Without them it's looking for the variable "userid" rather than the key name "userid".

Coldfusion validate list of emails

I am trying to validate a list of emails that have been pulled from the database.
<cfquery name="AdminEmail" datasource="#blah#">
Select email from users where role = "admin"
<cfquery>
<cfset variable.mailto = #adminemail.Email#>
The query would return multiple emails which is fine for cfmail, but IsValid only validates a single variable. Any advice. This is needed to get to the security standards asked of me.
Loop through the query of your emails and then add them to a new variable if they're valid.
<cfset validEmails = []>
<cfloop query="adminemail">
<cfif isValid('email', adminemail.email)>
<cfset arrayAppend(validEmails, adminemail.email)>
</cfif>
</cfloop>
<cfset mailTo = arrayToList(validEmails)>
Note: I used an array to store the emails because appending to a list is a more costly process and an array will be slightly faster. Probably nothing you'll notice unless you have hundreds of emails but still a good practice.

Getting prevalue id from umbraco dropdown list

I'm currently trying to implement AJAX results filtering on a certain page.
I created the dropdowns(on the client side), so that they have the umbraco prevalue id as their value.
I will then send this id to the server, rather than the text value. Then I loop through my content to find items with this same id.
The problem, however, is that I can't figure out how to get the value id from the property. Everything either returns the text value, or just a 0 value.
This is being performed in an ApiController.
These are all of the options I've tried:
IPublishedContent root = Umbraco.TypedContentAtRoot().First();
var downloads = root.Children.Where(q => q.Name == "Downloads").SingleOrDefault();
foreach (var item in downloads.Children)
{
var test = item.GetPropertyValue<int>("classification");
var testing = item.GetProperty("classification");
var testVal = testing.DataValue;
var testValToo = testing.GetValue<int>();
var testThree = testing.Value;
}
These are the results in order:
- 0
- IPublishedProperty
- "textValue"
- 0
- "textValue"
Is it possible to get the selected value id from a dropdownlist property? Or is string matching my only option to compare values?
EDIT:
Nevermind, found the solution. Posting the answer here, in case someone else needs it.
I was using the data type dropdownlist. I should have been using dropdownlist:publishing keys.
dropdownlist only ever returns a value. dropdownlist:publishing keys, however, returns the prevalue id, rather than the text value.
Source
Something like this perhaps.
library.GetPreValueAsString(node.GetProperty<int>("sectionType")).ToLower()

Table with a foreign key

how can I build a table of "orders" containing "IdOrder", "Description" and "User"?... the "User" field is a reference to the table "Users", which has "IdUser" and "Name". I'm using repositories.
I have this repository:
Repository<Orders> ordersRepo = new OrderRepo<Orders>(unitOfWork.Session);
to return all Orders to View, I just do:
return View(ordersRepo.All());
But this will result in something like:
IdOrder:1 -- Description: SomeTest -- User: UserProxy123ih12i3123ih12i3uh123
-
When the expected result was:
IdOrder:1 -- Description: SomeTest -- User: Thiago.
PS: I don't know why it returns this "UserProxy123ih12i3123ih12i3uh123". In Db there is a valid value.
The View:
It is showed in a foreach (var item in Model).
#item.Description
#item.User //--> If it is #item.User.Name doesn't work.
What I have to do to put the Name on this list? May I have to do a query using LINQ - NHibernate?
Tks.
What type of ORM are you using? You mention "repositories" but does that mean LinqToSql, Entity Framework, NHibernate, or other?
It looks like you are getting an error because the User field is not loaded as part of the original query. This is likely done to reduce the size of the result set by excluding the related fields from the original query for Orders.
There are a couple of options to work around this:
Set up the repository (or context, depending on the ORM) to include the User property in the result set.
Explicitly load the User property before you access it. Note that this would be an additional round-trip to the database and should not be done in a loop.
In cases where you know that you need the User information it would make sense to ensure that this data in returned from the original query. If you are using LinqToSql take a look at the DataLoadOptions type. You can use this type to specify which relationships you want to retrieve with the query:
var options = new DataLoadOptions();
options.LoadWith<Orders>(o => o.User);
DataContext context = ...;
context.LoadOptions = options;
var query = from o in context.Orders
select o;
There should be similar methods to achive the same thing whatever ORM you are using.
In NHibernate you can do the following:
using (ISession session = SessionFactory.OpenSession())
{
var orders = session.Get<Order>(someId);
NHibernateUtil.Initialize(orders.User);
}
This will result in only two database trips (regardless of the number of orders returned). More information on this can be found here.
In asp.net MVC the foreign key doesn't work the way you are using it. I believe you have to set the user to a variable like this:
User user = #item.User;
Or you have to load the reference sometimes. I don't know why this is but in my experience if I put this line before doing something with a foreign key it works
#item.UserReference.load();
Maybe when you access item.User.Name the session is already closed so NHib cannot load appropriate user from the DB.
You can create some model and initialize it with proper values at the controller. Also you can disable lazy loading for Orders.User in your mapping.
But maybe it is an other problem. What do you have when accessing "#item.User.Name" from your View?

Using a session variable in the where clause of a LINQ statement

Good afternoon all.
I have a page that displays data in a gridview based upon what the user selects for a material in a radiobutton list and how many they wish to see, a text box.
Upon logging into this page, a session variable for MemberID is created, MemberKey.
What I would like to do is pass this session variable into the LINQ statement so that only the specific member that has logged in sees their data:
ContextTypeName="VDSWeightsReportingService.CompleteWeightsDataContext" EnableInsert="True"
EnableUpdate="True" TableName="tblOnlineReportingCOMPLETEWEIGHTSFINALDEMOs"
Where="MaterialText == #MaterialText && Productpriority <= #Productpriority && MemberId == #MemberId">
<WhereParameters>
<asp:ControlParameter ControlID="radMaterial" Name="MaterialText"
PropertyName="SelectedValue" Type="String" />
<asp:ControlParameter ControlID="tbxHowMany" Name="Productpriority"
PropertyName="Text" Type="Int32" />
<asp:SessionParameter Name="MemberId" SessionField="MemberKey"
Type="String" />
</WhereParameters>
</asp:LinqDataSource>
I have tried to insert the session variable as above but without the LINQ no longer seems to go through the motions.
Can someone point out to me where I am going wrong?
If this doesn't work, or is not possible, can someone advise of a way around this? i.e. using this session variable in the LINQ where clause.
Make sure you select the correct session variable!!!!

Resources