I'm having problems using an HQL query to get data from a related entity.
I have a 'Photoshoot' entity with a one to many relationship to an 'Image' entity.
I'm trying to pull all images that belong to a particular Photoshoot, which I want to do with an HQL query so that I can get some specific filtering in.
What I'm getting back is this:
Unable to resolve path [Photoshoot.sPhotoshootGUID], unexpected token [Photoshoot] [FROM Image WHERE Photoshoot.sPhotoshootGUID = '889440aa-a12a-11e1-8edb-d02788828044']
I can't figure out why - if I pull back the Photoshoot, I can easily get to the associated images using the 'getImages()' function. If I use exactly the same code to get another related entity it seems to work fine!
Here's the code for my entities:
--- Image ---
<cfcomponent persistent="true" entityname="Image" table="tblImages_Base">
<!--- Identifier --->
<cfproperty name="sImageGUID" fieldtype="id" generator="guid" setter="false" />
<!--- Properties --->
<cfproperty name="sFileName" ormtype="string" />
<cfproperty name="sImageFolder" ormtype="string" dbdefault="" />
<cfproperty name="Active" ormtype="boolean" default=0 dbdefault=0 notnull="true" />
<!--- Many Images can belong to a single Photoshoot --->
<cfproperty name="Photoshoot"
fieldtype="many-to-one"
cfc="Photoshoot"
fkcolumn="fk_sPhotoshootGUID"
fetch="join"
inverse="true"
/>
</cfcomponent>
--- Photoshoot ---
<cfcomponent persistent="true" entityname="Photoshoot" table="tblPhotoshoots">
<!--- Identifier --->
<cfproperty name="sPhotoshootGUID" fieldtype="id" generator="guid" setter="false" />
<!--- Properties --->
<cfproperty name="Active" ormtype="boolean" default=0 dbdefault=0 notnull="true" />
<cfproperty name="l_ImageOrder" ormtype="text" />
<!--- One Photoshoot can contain many Images --->
<cfproperty name="Images"
fieldtype="one-to-many"
cfc="Image"
fkcolumn="fk_sPhotoshootGUID"
type="array"
singularname="Image"
/>
</cfcomponent>
--- HQL Query ---
<cfquery name="Local.objPhotoshootImages" dbtype="hql">
FROM Image
WHERE Photoshoot.sPhotoshootGUID = '889440aa-a12a-11e1-8edb-d02788828044'
</cfquery>
If it makes a difference, I'm running on Railo 3.3.3.000
I'm not sure why your HQL is failing - that error can be due to case-sensitivity, but "Photoshoot" seems to be in the correct case in the code you've posted.
As a workaround you could try adjusting your HQL to make the join explicit:
<cfquery name="Local.objPhotoshootImages" dbtype="hql">
FROM Image
WHERE fk_sPhotoshootGUID = '889440aa-a12a-11e1-8edb-d02788828044'
</cfquery>
Related
I am working on adding to a ColdFusion 2016 application with ORM. The application pulls up and doesn't give any type of errors prior to adding the second table code (TableTwo). As soon as the second table code is added, it gives an error saying:
Can't create table XXXXX.YYYYY (errno: 150 "Foreign key constraint
is incorrectly formed")
Where XXXXX is the name of the application as a whole - not TableOne, TableTwo or BaseTable.
Are there any ideas as to what is causing the application to give such an error?
If I delete all references to TableTwo and reload ORM, the application will pull up again. TableOne and TableTwo need to join to the BaseTable, but will not join to each other.
Below is an example of how the code is currently formatted.
TableOne.cfc
component {
property name="id" fieldType="id" ormtype="int" type="numeric" generator="native";
property name="baseTableID" ormtype="int" type="numeric" insert="false" update="false";
//relations
property name"baseTable" fieldType="one-to-one" cfc="BaseTable" fkcolumn="baseTableID" joincolumn="id" notnull="true" casecade="save-update";
}
BaseTable.cfc
component {
property name="id" fieldType="id" ormtype="int" type="numeric" generator="native";
//relations
property name="TableOne" fieldtype="one-to-one" cfc="TableOne" mappedby="baseTable" cascade="all-delete-orphan";
--Attempting to add a second one
property name="TableTwo" fieldtype="one-to-one" cfc="TableTwo" mappedby="baseTable" cascade="all-delete-orphan";
}
TableTwo.cfc
component {
property name="id" fieldType="id" ormtype="int" type="numeric" generator="native";
property name="baseTableID" ormtype="int" type="numeric" insert="false" update="false";
//relations
property name"BaseTable" fieldType="one-to-one" cfc="BaseTable" fkcolumn="baseTableID" joincolumn="id" notnull="true" casecade="save-update";
}
Is it possible to have a read-only collection on an entity where the collection is populated by a custom SQL query?
I have 3 classes - Village, Report, and Army - each backed by a table. I want a Village to have a property "ReportsAsDefender", which is a collection of Reports where the defending Army in that Report belongs to the given Village:
SELECT
village.Id as VillageId, report.*
FROM
armies army
join reports report
on report.DefendingArmyId = army.Id
join villages village
on village.Id = army.VillageId
I want the results of this query accessible as a collection on my Village class. This may be doable using only XML mapping but I can't find anything that would be helpful here.
I'm not using Fluent.
Edit 1: I've uploaded my current source code and sample SQL data so that my issues can be reproduced: https://github.com/tylercamp/NHTW
I've also updated the SQL query above to match my current changes.
With the changes suggested by #RadimKöhler, I get an exception when invoking someVillage.ReportsAsDefender.ToList(): could not initialize a collection:, followed by some nonsensical MySQL:
SELECT
reportsasd0_.VillageId as villageid11_4_1_,
reportsasd0_.Id as id1_4_1_,
reportsasd0_.Id as id1_4_0_,
reportsasd0_.TribalWarsId as tribalwarsid2_4_0_,
reportsasd0_.WorldId as worldid3_4_0_,
--- ... and a for more nonsensical "selects"
FROM Reports reportsasd0_ WHERE reportsasd0_.VillageId=?
I have no clue where "asd" comes from, nor any of the other formatting. The string "asd" does not appear anywhere in my codebase.
The relevant entities from my .hbm.xml file contains:
<class name="Village" table="Villages">
<id name="Id">
<generator class="increment" />
</id>
<property name="TribalWarsId" />
<property name="WorldId" />
<property name="Name" />
<property name="OwnerId" />
<!-- Where "villa_reports_as_defender" is the name of the view query shown above -->
<bag name="ReportsAsDefender" table="villa_reports_as_defender" mutable="false" lazy="true" inverse="true">
<key column="VillageId" />
<one-to-many class="Report"/>
</bag>
</class>
<!-- Report -->
<class name="Report" table="Reports">
<id name="Id">
<generator class="increment" />
</id>
<property name="TribalWarsId" />
<property name="WorldId" />
<property name="AttackingArmyId" />
<property name="DefendingArmyId" />
<property name="RemainingAttackingArmyId" />
<property name="RemainingDefendingArmyId" />
<property name="DodgedArmyId" />
<property name="OccurredAt" />
<property name="LaunchedAt" />
</class>
My Village class has the following property:
public virtual ICollection<Report> ReportsAsDefender { get; set; }
Any related data should be mapped as a standard entity. Even if that would be a view (question could be how effective data loading we will experience...)
Such view must have a relation column (e.g. Parent_ID). That could be expressed as a many-to-one in the child mapping:
<many-to-one name="Parent" column="Parent_ID" ... />
and exactly that column we must use in the parent mapping
<bag name="Children"
lazy="true"
inverse="true"
batch-size="25"
cascade="all-delete-orphan" >
// This columns is the same as for many-to-one
<key column="Parent_ID" />
<one-to-many class="Child" />
</bag>
Check all the details here:
Minimal and correct way to map one-to-many with NHibernate
I have a many to many relationship setup, and need to control the order.
I have an entity with the property below. How do I control the order of the components when retrieved via this relationship?
property name="Components" fieldtype="many-to-many" cfc="CmsComponent"
type="array"
singularname="Component"
linktable="CMSPageComponents"
fkcolumn="page_id"
inversejoincolumn="component_id";
I've setup a column in the linktable (CMSPageComponents) called dispOrder. But when I set the orderby="dispOrder" or orderby="CMSPageComponents.dispOrder" attribute on the property above, it just seems to ignore it.
Any suggestions on how I can control the order of a many-to-many relationship?
When the relationship is many-to-many CF will apply the orderBy statement to the object table not to the link table. So in theory you could move your dispOrder column from the CMSPageComponents link table to the CmsComponent table to make it work.
But in practice I expect the ordering is specific to the many-to-many relationship (i.e. the particular page), in which case you could follow Peter's advice and create a separate entity which links the other two entities and lets you define an order property.
So you would have 3 entities:
CmsPage
CmsComponent
CmsPageComponent
CmsPageComponent might look something like this:
<cfcomponent displayname="CmsPageComponent" persistent="true" table="cmsPageComponents">
<!--- Add a primary key for the link Entity --->
<cfproperty name="ID" fieldType="id" generator="native">
<cfproperty name="dispOrder">
<cfproperty name="page" fieldType="many-to-one" cfc="CmsPage" fkColumn="pageID">
<cfproperty name="component" fieldType="many-to-one" cfc="CmsComponent" fkColumn="componentID">
<!--- init() etc --->
</cfcomponent>
CmsPage could then have a one-to-many relationship with the link entity allowing ordering using the dispOrder column:
<cfcomponent displayname="CmsPage" persistent="true" table="cmsPages">
<cfproperty name="ID" fieldType="id" generator="native">
<cfproperty name="pageComponents" singularName="pageComponent" fieldType="one-to-many" cfc="PageComponent" fkColumn="pageID" orderBy="dispOrder">
<!--- init() etc --->
</cfcomponent>
Update
The following shows how you might add and display page components. Not the only or necessarily best way, but just to give you an idea:
<cfscript>
transaction{
//load the page
page = EntityLoadByPK( "CmsPage",1 );
//load the components we want to add
component1 = EntityLoadByPK( "CmsComponent",1 );
component2 = EntityLoadByPK( "CmsComponent",2 );
//create link objects
pageComponent1 = EntityNew( "CmsPageComponent" );
pageComponent2 = EntityNew( "CmsPageComponent" );
// link them to the pages and components in the order we want
pageComponent1.setComponent( component1 );
pageComponent1.setPage( page );
pageComponent1.setDispOrder( 2 );
EntitySave( pageComponent1 );
pageComponent2.setComponent( component2 );
pageComponent2.setPage( page );
pageComponent2.setDispOrder( 1 );
EntitySave( pageComponent2 );
}
//Reload from the database so the order is applied
EntityReload( page );
</cfscript>
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<cfoutput>
<h2>Page #page.getID()#</h2>
<ol>
<cfloop array="#page.getPageComponents()#" index="pageComponent">
<cfset component = pageComponent.getComponent()>
<li>Component ID #component.getID()#, Display Order = #pageComponent.getDispOrder()#)</li>
</cfloop>
</ol>
</cfoutput>
</body>
</html>
NOTE: this assumes the ORM setting flushAtRequestEnd is true in Application.cfc
I am using ColdFusion ORM with FW/1.
I have two tables student and parent, I have given many-to-one relationship as we know parent can have more wards in a school. I am adding student and parent separately, while adding parent I need parentId to be stored in student table so that I can list or get student with their parents for further features and activity.
Can anyone help me out how should I save the parent in a parent table and also parentId in student table?
student.cfc
component output="false" persistent="true" accessors="true" entityname="Student" table="school_student" {
// Use a mysql autonumber for an ID
property name="StudentId" column="school_studentid" type=numeric fieldtype="id" generator="identity";
property name="Fullname" column="school_studentFullname" type="string" length="128" notnull="true";
property name="email" column="school_studentEmail" type="string" length="128" notnull="true";
property name="password" column="school_studentPassword" type="string" length="64";
property name="Parent" fieldtype="many-to-one" cfc="Parent" fkcolumn="student_school_parentId" lazy="true" singularname="Parent";
}
parent.cfc
component output="false" accessors="true" persistent="true" entityname="Parent" table="school_parent" {
//use mysql autonumber id
property name="parentId" fieldtype="id" column="school_parentid" generator="identity";
property name="name" type="string" column="school_parentname" length="128";
property name="email" type="string" column="school_parentemail" length="128" ;
property name="password" type="string" column="school_parentpassword" length="64";
//relate parent with Student.
property name="Student" fieldtype="one-to-many" cfc="Student" fkcolumn="student_school_parentId" lazy="extra" inverse="true";
This is the way i am saving parent in my controllers:
<cfargument name="rc" type="struct" required="true">
<cfset parent = getParentService().parent(arguments.rc.parentid)>
<cfset student = getStudentService().student(arguments.rc.studentId)>
<cfset parent.setName(arguments.rc.name)>
<cfset parent.setEmail(arguments.rc.email)>
<cfset parent.setPassword(arguments.rc.password)>
<cfset getParentService().save(parent)>
<cfset student.addparent(parent)>
<cfset variables.fw.redirect('parent.list')>
How can I save parentid in student table while saving parent? I mean how can i call student save method to have parentid in student table?
Any help would be appreciated.
thanks
Try this
<cfset parent.addstudent(student)>
<cfset getParentService().save(parent)>
And try setting cascade="any" on the student property of Parent. This should allow you to save both objects...even if they are both are new objects being persisted for the first time.
I have a coldfusion component that is uneditable, only echos strings, and does not return a variable(and there is no return * statement). How can I grab this echoed string and place it in a variable before it is displayed directly on screen?
So :
<cfcomponent displayname="Helpz">
<cffunction name="OutputString" returnType="void" output="yes">
I love Stack overflow
</cffunction>
The outputted string needs to be stored into a variable.
CFSavecontent is what you need.
<cfsavecontent variable="myString"><cfset object.outputString() /></cfsavecontent>
Then you can do anything you want with #myString#.
<cfsavecontent variable="foo">
<cfset myComponent.outputString()>
</cfsavecontent>
It's probably a better practice to avoid that kind of output from within a function. An alternative solution would be:
<cfcomponent displayname="Helpz">
<cffunction name="getString" returnType="string" output="no">
<cfset var myString = "">
<cfsavecontent variable="myString">I love Stack overflow</cfsavecontent>
<cfreturn myString>
</cffunction>
</cfcomponent>
and then in you're template or wherever:
<cfoutput>#myCfc.getString()#</cfoutput>