NHibernate Collection Property from Query (Non-Fluent) - nhibernate

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

Related

Adding onto an existing ColdFusion 2016 ORM application

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";
}

Set <chart:guide> value at runtime

I'm trying to access the
<chart:guide>
value property from the screen controller, but I can't find any getter to reach it. The xml block is like this:
<chart:valueAxes>
<chart:axis position="LEFT"
stackType="REGULAR"
title="Graph Title">
<chart:guides>
<chart:guide
value="0"
inside="true"
lineAlpha="1"
/>
</chart:guides>
</chart:axis>
</chart:valueAxes>
I need to set the value of the guide at runtime. Any suggestion?
Let's say we have the following SerialChart:
<chart:serialChart id="serialChart"
caption="Serial chart"
height="100%"
width="100%"
categoryField="x">
<chart:graphs>
<chart:graph valueField="y"/>
</chart:graphs>
<chart:valueAxes>
<chart:axis position="LEFT">
<chart:guides>
<chart:guide value="12"
inside="true"
lineAlpha="1"/>
</chart:guides>
</chart:axis>
</chart:valueAxes>
<chart:data>
<chart:item>
<chart:property name="x" value="10"/>
<chart:property name="y" value="12"/>
</chart:item>
<chart:item>
<chart:property name="x" value="11"/>
<chart:property name="y" value="2"/>
</chart:item>
<chart:item>
<chart:property name="x" value="12"/>
<chart:property name="y" value="120"/>
</chart:item>
<chart:item>
<chart:property name="x" value="13"/>
<chart:property name="y" value="16"/>
</chart:item>
</chart:data>
</chart:serialChart>
You can simply get ValueAxis and then get Guide object by index or iterate collection and find by id (optional attribute of Guide):
#Inject
private SerialChart serialChart;
ValueAxis valueAxis = serialChart.getValueAxes().get(0);
Guide guide = valueAxis.getGuides().get(0);
guide.setValue(15);
serialChart.repaint();
Note, if we want to change already displayed chart configuration then we have to call repaint() method.
If you use CUBA 6.4 or older, you have to obtain Configuration object first using getConfiguration() method and cast it to appropriate chart type as shown here: https://doc.cuba-platform.com/charts-6.4/cdp_screen_controller.html

while adding records separately using many-to-one relationship getting variable undefined

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.

Coldfusion HQL query with relationships - unable to resolve path

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>

LINQ to XML. Enumeration yielded no results

I'm having trouble populating an object from an XML file. I've copied an example I've found almost exactly, with variable names changed, but I keep getting the "Enumeration yielded no results" exception.
Here is my code:
Dim element As XElement = XElement.Load(path)
Dim itemProps = From p In element...<Property> _
Where p.<LanguageCode>.Value = "en_us" _
Select p.<Title>.Value, p.<Description>.Value
Using breakpoints, I have confirmed that the 'element' variable is being properly populated using the XElement.Load(path) method.
Here is the XML file that is being accessed:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Items>
<Item ItemID="1">
<Property ItemPropertyID="1">
<Title>Title1</Title>
<Description>Description1</Description>
<LanguageCode>en-us</LanguageCode>
</Property>
</Item>
<Item ItemID="2">
<Property ItemPropertyID="2">
<Title>Title2</Title>
<Description>Description2</Description>
<LanguageCode>en-us</LanguageCode>
</Property>
</Item>
<Item ItemID="3">
<Property ItemPropertyID="3">
<Title>Title3</Title>
<Description>Description3</Description>
<LanguageCode>en-us</LanguageCode>
</Property>
</Item>
<Item ItemID="4">
<Property ItemPropertyID="4">
<Title>Title4</Title>
<Description>Description4</Description>
<LanguageCode>en-us</LanguageCode>
</Property>
</Item>
<Item ItemID="5">
<Property ItemPropertyID="5">
<Title>Title5</Title>
<Description>Description5</Description>
<LanguageCode>en-us</LanguageCode>
</Property>
</Item>
<Item ItemID="6">
<Property ItemPropertyID="6">
<Title>Title6</Title>
<Description>Description6</Description>
<LanguageCode>en-us</LanguageCode>
</Property>
</Item>
</Items>
Essentially, the XML query is supposed to return the title and the description for every Property which has an element called Language Code, which is equal to "en-us". I have a feeling that my problem lies in my XML code.
This language code:
en_us
should be:
en-us
Try taking one of the dots out of
Dim itemProps = From p In element...<Property>
Your going 3 levels down, when you only need to go down 2.
If that doesn't work try just one dot, because essentially the path your travelling is only 1 below the root of the document.