I have an Coldfusion orm application that have two object:
Widget.cfc
// Primary Key
property name="id" fieldtype="id" column="" generator="native";
// Properties
property name="col" type="string";
property name="created_at" type="date";
property name="kind" type="string";
property name="name" type="string";
property name="label" type="string";
property name="range" type="string";
property name="row" type="numeric";
property name="size" type="numeric";
property name="size_x" type="numeric";
property name="size_y" type="numeric";
property name="source" type="string" default="null";
property name="targets" type="numeric";
property name="update_interval" ormtype="int";
property name="update_at" type="date";
//Relationship
property name="dashboards" fieldtype="many-to-many"
linktable="DashboardWidgets"
type="array" cfc="dashboard"
cascade="all-delete-orphan" inverse="true" singularname="dashboard";
And dashboard.cfc
// Primary Key
property name="id" fieldtype="id" column="id" generator="native";
// Properties
property name="name" type="string";
property name="time" type="timestamp";
property name="layout" type="string";
property name="created_at" type="timestamp";
property name="updated_at" type="timestamp";
property name="locked" type="boolean";
//Relationships
property name="widgets" fieldtype="many-to-many"
linktable="DashboardWidgets" type="array" cfc="widget"
cascade="all-delete-orphan" singularname="widget";
I need to output as json all the property of widget.cfc and also the dashboard id that is defined in the relationship.
So what I have is something like:
[{"id":5,"kind":"number",
"name":"dsfasdfa",
"size_x":1,
"size_y":1,
"source":"demo",
"update_interval":36000,
"dashboards":[{"id":3,"name":"Undefined name",
"time":"July, 24 2013 20:52:44 +0200",
"layout":"test",
"created_at":"July, 24 2013 20:52:44 +0200",
"updated_at":"July, 24 2013 20:52:44 +0200",
"locked":false,
"widgets":null}]
}]
What I need insted is something like:
[{"id":5,
"kind":"number",
"name":"dsfasdfa",
"size_x":1,
"size_y":1,
"source":"demo",
"update_interval":36000,
"dashboard_id":3
}]
How can I achieve this? I need only the id of the dashboard.
I've found a way to obtain this in the documentation:
<cfproperty name="art"
fieldtype="one-to-many"
cfc="ART"
fkcolumn="artistId"
lazy="true">
Related
Repeated column in mapping for entity: user column: userid (should be mapped with insert="false" update="false")
That is the error message I'm getting. I've got a user table (customer) that is self-referential. That way I can tell which user created which and when.
Here is my entity.
component table="customer" output="false" accessors="true" persistent="true" {
property name="userid" column="userid" ormtype="int" fieldtype="id" generator="identity";
property name="firstname" column="firstname" ormtype="string";
property name="lastname" column="lastname" ormtype="string";
property name="email" column="email" ormtype="string";
property name="active" column="active" type="boolean" ormtype="boolean";
property name="createdOn" column="createdOn" ormtype="date";
property name="modifiedOn" column="modifiedOn" ormtype="date";
property name="createdBy" fieldtype="one-to-one" cfc="user" fkcolumn="userid" inverse="true";
property name="modifiedBy" fieldtype="one-to-one" cfc="user" fkcolumn="userid" inverse="true";
}
I've added what the error message tells me to add to each property so they now look like:
property name="createdBy" fieldtype="one-to-one" cfc="user" fkcolumn="userid" inverse="true" insert="false" update="false";
property name="modifiedBy" fieldtype="one-to-one" cfc="user" fkcolumn="userid" inverse="true" insert="false" update="false";
SOLUTION:
I added inversejoincolumn="userid" and it worked. See below
property name="createdBy" column="createdBy" fieldtype="one-to-one" cfc="user" inversejoincolumn="userid";
property name="modifiedBy" column="modifiedBy" fieldtype="one-to-one" cfc="user" inversejoincolumn="userid";
In your customers table create separate columns to record the IDs of the users who do the creating and modifying. You could call them creatorid and modifierid.
Then change the fkcolumn in your createdBy and modifiedBy relationships from userid to creatorid and modifierid respectively.
How do I map relationship, where child endpoint is exposed via Id property and not via whole Parent object?
Here is the example:
class Parent {
public Guid Id { get; set; }
public List<Child> Chlidren { get; set; }
}
class Child {
public Guid Id { get; set; }
public Guid ParentId { get; set; }
}
Here are the equivalent mappings I'm using:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Blabla"
namespace="Blabla"
auto-import="false">
<typedef name="ChildrenList" class="Blabla" />
<class name="Parent" table="Parent" lazy="false">
<id name="Id" column="ID" type="Guid">
<generator class="guid" />
</id>
<bag name="Children" table="Child"
cascade="save-update"
collection-type="ChildrenList"
lazy="false">
<key column="ParentID" not-null="true" />
<one-to-many class="Child" />
</bag>
</class>
<class name="Child" table="Child" lazy="false">
<id name="Id" column="ID" type="Guid">
<generator class="guid" />
</id>
<!-- How to map ParentID here? -->
</class>
</hibernate-mapping>
When I create a parent, add some children to Children collection and then save the parent, everything is fine. But if save a parent object first, then create a child, setting its ParentID property to ID of the parent, then I get
NHibernate.PropertyValueException:
not-null property references a null or transient value Child._Parent.ChildrenBackref
All attempts to map many-to-one relationship resulted in different exceptions while creating NHibernate configuration. Mostly about object type mismatch.
I'm sure NHibernate is capable to handle this scenario. There must something fairly basic that I miss.
EDIT:
I think it make sense to the example test, which fails with above exception:
var child = new Child(Create.Saved<Parent>().Id); // this sets the ParentId property
this.Repository.Save(child); // here I get the exception
My thoughts why NHibernate is raising this: Children property of Parent class mapped in a way that says that a child cannot exist without a parent (<key column="ParentID" not-null="true" />). When I try to persist a child, NHibernate tries to resolve this relationship (to find a parent this child relates to) and fails, since being given no child endpoint (which otherwise would be ParentId property) in the mapping, it check for its own Child._Parent.ChildrenBackref endpoint, whatever it is.
This looks like a desired solution: Mapping ParentId property as child endpoint of the relationship. This would force NHibernate to resolve a parent by using value of ParentId property as parent's primary key.
The thing is I don't know if it's possible.
The one-to-many / many-to-one relationships you have in NHibernate always needs to have a dominant side (i.e. the side that manages the "saving").
<bag name="Children" table="Child"
cascade="save-update"
collection-type="ChildrenList"
lazy="false">
<key column="ParentID" not-null="true" />
<one-to-many class="Child" />
</bag>
The above is a one-to-many relationship where the dominant side is the parent. That means, you save the parent ... and that will save the parent first, then, the children (with the ParentId being null), then a subsequent update will be issued to set the child.ParentId.
Note:
The child is inserted first with ParentId=null ... if you have a db or mapping restriction to say ParentId cannot be null, this action will fail.
<bag name="Children" table="Child"
cascade="save-update"
collection-type="ChildrenList"
lazy="false"
inverse=true>
<key column="ParentID" not-null="true" />
<one-to-many class="Child" />
</bag>
Note the inverse=true attribute. This means the child object is dominant in the relationship, meaning the child object is in charge. The parent will be inserted, then the Id will be assiged to the child.ParentId, and then the child will be inserted with the ParentId already set.
In many cases, of course, you want to go either way. The easiest way to do this is to manage the relationship on both ends (unfortunately, you have to do this yourself).
On the Parent, you have a method:
public void AddChild(Child child)
{
Children.Add(child);
child.ParentId = Id;
}
public void RemoveChild(Child child)
{
Children.Remove(child);
child.ParentId = null;
}
On the Child, you have a method:
public void SetParent(Parent parent)
{
ParentId = parent.Id;
parent.Children.Add(this);
}
Using these methods to Add/Remove/Set, both sides are consistent after the action is performed. It, then, wouldn't matter whether you set inverse=true on the bag or not.
see http://www.nhforge.org/doc/nh/en/index.html#collections-example
Say I have an immutable ICompositeUserType to deal with a DateRange, or Money, and then it turns out that I have another value object (ie, immutable) that has either a DateRange or Money property value in it. For example, a Name that has an EffectivePeriod (DateRange).
The DataRangeUserType encapsulates some logic I wouldn't want duplicated.
Can I reuse my DataRangeUserType inside of a NameUserType? How?
Cheers,
Berryl
UPDATE
Below is the summary comment on ICompositeUserType taken from the NHibernate source code which suggests what I am thinking of can be done, just not sure how. Admittedly, the component strategy is easy and works great, until you think you might want to use the same compoent elsewhere
/// <summary>
/// A UserType that may be dereferenced in a query.
/// This interface allows a custom type to define "properties".
/// These need not necessarily correspond to physical .NET style properties.
///
/// A ICompositeUserType may be used in almost every way
/// that a component may be used. It may even contain many-to-one
/// associations.
///
/// ...
/// </summary>
Using component mapping
<component name="MyCompositeComponent" class="...">
<property name="Name" not-null="true" length="50"/>
<property name="Price" type="...MoneyUserType">
<column name="Amount"/>
<column name="Currency"/>
</property>
<property name="EffectivePeriod" type="...DateRangeUserType">
<column name="EffectiveStart"/>
<column name="EffectiveEnd"/>
</property>
</component>
Hibernate lets you compose value types in Components:
<class name="MyClass" table="MyTable" >
...
<component name="_namedPeriod">
<property name="_name" column="PeriodName" />
<property name="_effectivePeriod"
type="MyNamespace.DataRangeUserType, MyAssembly" >
<column name="PeriodStart" />
<column name="PeriodEnd" />
</property>
</component>
...
</class>
Classes look like this:
// entity
public class MyClass {
private NamedPeriod _namedPeriod;
}
// immutable value object
public class NamedPeriod {
private readonly String _name;
// immutable value object
private readonly DateRange _effectivePeriod;
}
The idea that you use UserTypes for primitives like DateRange and Money and Component for a larger immutable value objects. Components can also include other components.
I'm trying to figure what's the correct way to map the following parent child relationship. I have a parent class which contains child objects. However, the parent also has a pointer to an instance of one of the children (the PrimaryChild)
Class Parent
Public Property Id As Integer?
Public Property PrimaryChild As Child
Public Property Children As IList(Of Child)
End Class
Public Class Child
Public Property Id As Integer?
Public MyParent As Parent
End Class
Usage is something like
Dim ch As New Child
Dim par as New Parent
ch.MyParent = par
par.Children.Add(ch)
par.PrimaryChild = ch
Session.SaveOrUpdate(par)
However, when I do this, the PrimaryChild is shown as being a null or transient value. I have set cascade="all" on the Children collection.
Any ideas what I'm doing wrong?
Update 1
Added Mappings
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
<class xmlns="urn:nhibernate-mapping-2.2" mutable="true" name="Parent" table="Parents">
<id name="Id" type="System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ID" />
</id>
<set access="nosetter.camelcase-underscore" cascade="all-delete-orphan" inverse="true" name="Children" mutable="true">
<key>
<column name="ParentID" />
</key>
<one-to-many class="Child" />
</set>
<many-to-one cascade="save-update" class="Child" name="PrimaryChild">
<column name="PrimaryChildID" not-null="true" />
</many-to-one>
<many-to-one cascade="save-update" class="Child" name="SecondaryChild">
<column name="SecondaryChildID" not-null="true" />
</many-to-one>
</class>
</hibernate-mapping>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
<class xmlns="urn:nhibernate-mapping-2.2" mutable="true" name="Child" table="Child">
<id name="Id" type="System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ID" />
</id>
<many-to-one class="Parent" name="Parent">
<column name="ParentID" not-null="true" />
</many-to-one>
</class>
</hibernate-mapping>
Your tables are looking like this:
Table Parent
(
...
PrimaryChild_FK NOT NULL
)
Table Child
(
...
Paren_FK NOT NULL
)
Can you tell me in which order the data should be inserted? You can neither insert Parent nor Child, since both need the other to set the foreign key. (NHibernate inserts one of them and set the FK to null, to update it later. But the database complains.)
Remove the not null constraint from the set. NHibernate is not smart enough to find a working insert order if you just remove one of them. (AFAIK, not null constraints in the mapping files are actually only used to create the database schema from).
And as already mentioned by mathieu, make the set inverse and use the same foreign key for the child-parent and the parent-children relations.
I've performed this task with tools like the NHibernate LINQ library.
public class Parent {
public Parent() {
Children = new List<Child>();
}
public virtual IList<Child> Children { get; set; }
public virtual Child PrimaryChild {
get {
return Children.FirstOrDefault(x => x.IsPrimary);
}
}
}
If you've already loaded the children, then PrimaryChild is an in-memory operation. If you request PrimaryChild first, then this will be it own database fetch operation. Works nicely, IMO.
And you should look at Andrew Bullock's response. Exposing an IList opens the door to bad domain design. You should only expose the enumeration.
What mappings do you have so far?
PrimaryChild is a one-to-one, Children is a one-to-many but you could manage the relationship in many different ways. Where are your Foreign Keys?
if you put the FK on the Child, then you want both one-to-one and one-to-many mappings with inverse=true set on both.
As an aside, this:
ch.MyParent = par
par.Children.Add(ch)
is a massive OO encapsulation fail. Parent shouldn't expose an IList, as other objects can manipulate it. The parent class should control all manipulations of itself. Make it an IEnumerable and use an AddChild method that does the above two lines.
If your relation is bidirectional (IE parent references children, and child references parent), and if the foreign key is on Child, you need to set the attribute
inverse="true"
in the declaration of the collection. Otherwise cascade won't work nicely :
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="Parent">
<id name="Id" />
<bag name="Children" cascade="all" inverse="true">
<key column="ID_PARENT" />
<one-to-many class="Child"/>
</bag>
</class>
<class name="Children">
<id name="Id" />
<many-to-one name="Parent" column="ID_PARENT" class="Parent" not-null="true" />
</class>
</hibernate-mapping>
I am trying to create a table-per-hierarchy mapping using NHibernate 2.0.1.
I have a base class with properties that exist for each subclass that other classes inherit from. All of these objects are persisted to one table called Messages that contain all of the possible fields for each class. There is a SourceID which is the discriminator and should indicate which Poco to return for each subclass. Here is my current mapping.
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="NS.Core"
namespace="NS.Core.Model">
<class name="BaseMessage" table="Messages">
<id name="MessageID" type="Int64">
<column name="MessageID" />
<generator class="native" />
</id>
<discriminator column="SourceID" type="Int32"/>
<property name="DateCreated" access="property" column="DateCreated" type="DateTime" not-null="true"/>
<property name="DatePublished" access="property" column="DatePublished" type="DateTime"/>
<property name="SourceID" access="property" column="SourceID" type="Int32"/>
<many-to-one name="User" column="UserID" access="property" cascade="none" lazy="false" fetch="join" outer-join="true" />
<subclass name="NMessage" discriminator-value="0">
<property name="Body" access="property" column="Body" type="String"/>
</subclass>
<subclass name="BMessage" discriminator-value="1">
<property name="Title" access="property" column="Title" type="String"/>
<property name="Body" access="property" column="Body" type="String"/>
</subclass>
<subclass name="CMessage" discriminator-value="2">
<property name="Url" access="property" column="Url" type="String"/>
<property name="Body" access="property" column="Body" type="String"/>
</subclass>
</class>
</hibernate-mapping>
I get an error querying saying Could not format discriminator value to SQL string of entity NS.Core.Model.BaseMessage so I put a discriminator value on this class too althout it should never return the base class. That led me to some antlr errors.
Am I taking the wrong approach to this problem? I would like to query the table and get back a list of different POCOs that all inherit from the base class. It would never return the base class itself.
below is the BaseMessage.cs
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Text;
namespace NS.Core.Model
{
[Serializable]
[DataContract]
[KnownType(typeof(User))]
public class BaseMessage
{
#region Private variables
private long _messageID;
private DateTime? _dateCreated;
private DateTime? _datePublished;
private int _sourceID;
private User _user = new User();
#endregion
#region Properties
[DataMember]
public virtual long MessageID
{
get { return _messageID; }
set { this._messageID = value; }
}
[DataMember]
public virtual DateTime? DateCreated
{
get { return _dateCreated; }
set { this._dateCreated = value; }
}
[DataMember]
public virtual DateTime? DatePublished
{
get { return _datePublished; }
set { this._datePublished = value; }
}
[DataMember]
public virtual int SourceID
{
get { return _sourceID; }
set { this._sourceID = value; }
}
[DataMember]
public virtual User User
{
get
{
if (this._user != null)
{ return this._user; }
else { return new User(); }
}
set { this._user = value; }
}
#endregion
}
}
The approach is sound. I have done exactly this several times.
You could make it explicit in your code my having BaseMessage's default constructor be protected.
You need to declare a discriminator-value on the base class as well.
I favor string values for discriminators, as this clearer when performing SQL queries or reports. Also, since instances of BaseMessage shoudl not exist, in would use null for its discriminator value.
<class name="BaseMessage" table="Messages" discriminator-value="null">
<id />
<discriminator column="SourceID" />
<subclass name="NMessage" discriminator-value="NMessage">
</subclass>
<subclass name="BMessage" discriminator-value="BMessage">
</subclass>
<subclass name="CMessage" discriminator-value="CMessage">
</subclass>
</class>
Also, I see that you have mapped a property to the discriminator column. You should instead have a method that returns something unique to the class - in this case the code.
Note that you cannot change the class of a mapped entity after it has been saved. Not even by changing the discriminator. If you did change it via SQL, your 2nd level cache will still hold a version with the original class.
class BaseMessage
{
public virtual string MessageType { return null; }
}
class NMessage : BaseMessage
{
public override string MessageType { return "NMessage"; }
}
Finally, your mapping file is overly verbose as it includes values which are the default. The following attributes and elements can be removed:
access="property" - this is the default
type="String" - all the types you use can be inferred from your .NET class
column="COL" - default is the same as the name
similarly for the id column element
All of your Message subclasses have property Body, so move it to the base class mapping. If this field can be longer than your database varchar, it should be a text column and have type="StringCLob" which maps to string in .NET
<class name="BaseMessage" table="Messages" discriminator-value="null">
<id name="MessageID">
<generator class="native" />
</id>
<discriminator column="SourceID"/>
<property name="DateCreated" />
<property name="DatePublished" />
<many-to-one name="User" column="UserID" cascade="none" lazy="false" fetch="join" outer-join="true" />
<property name="Body" type="StringCLob" />
<subclass name="NMessage" discriminator-value="NMessage">
</subclass>
<subclass name="BMessage" discriminator-value="BMessage">
<property name="Title" />
</subclass>
<subclass name="CMessage" discriminator-value="CMessage">
<property name="Url" />
</subclass>
</class>