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.
Related
I need to retrieve all the users with a valid Wish property (so not null). This is the xml of my class:
<class name="Project.Engine.Domain.User,Project.Engine" table="Users" lazy="true">
<id name="UserID" column="UserID">
<generator class="native" />
</id>
<property name="Firstname" column="Firstname" type="string" not-null="true"
length="255" />
<property name="Lastname" column="Lastname" type="string" not-null="true"
length="255" />
<property name="Email" column="Email" type="string" not-null="true"
length="255" />
<one-to-one name="Wish" cascade="all" property-ref="UserID"
class="Project.Engine.Domain.Wish, Project.Engine" />
</class>
The method to get all my users is the following:
public PagedList<User> GetAll(int pageIndex, int pageSize,
string orderBy, string orderByAscOrDesc)
{
using (ISession session = NHibernateHelper.OpenSession())
{
var users = session.CreateCriteria(typeof(User));
users.Add(Restrictions.IsNotNull("Wish"));
return users.PagedList<User>(session, pageIndex, pageSize);
}
}
As you can notice, I have added the Restriction on the child object. This doesn't work properly as the method return all users including the ones with Wish property as null. Any help?
this is the xml for child:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="Project.Engine.Domain.Wish,Project.Engine" table="Wish" lazy="false">
<id name="WishID" column="WishID">
<generator class="native" />
</id>
<property name="UserID" column="UserID" type="int" not-null="true" length="32" />
<property name="ContentText" column="ContentText" type="string" not-null="false" length="500" />
<property name="Views" column="Views" type="int" not-null="true" length="32" />
<property name="DateEntry" column="DateEntry" type="datetime" not-null="true" />
</class>
</hibernate-mapping>
Well, there is a bug with one-to-one and null testing of the side which may not exist. I had already encountered it but forgot about it. The property-ref just render it a bit more tricky to diagnose, but it does exist on actual one-to-one too.
Here is its corresponding issue in NHibernate tracking tool.
Workaround: test for null state of an non-nullable property of Wish, like Wish.Views.
Forgive the wild guess on test syntax, I do not use nhibernate-criteria anymore since years, but try by example:
public PagedList<User> GetAll(int pageIndex, int pageSize,
string orderBy, string orderByAscOrDesc)
{
using (ISession session = NHibernateHelper.OpenSession())
{
var users = session.CreateCriteria(typeof(User));
users.Add(Restrictions.IsNotNull("Wish.Views"));
return users.PagedList<User>(session, pageIndex, pageSize);
}
}
Using linq-to-nhibernate, I confirm this workaround works with my own projects, which gives by example:
// The "TotalAmount != null" seems to never be able to come false from a
// .Net run-time view, but converted to SQL, yes it can, if TransactionRecord
// does not exist.
// Beware, we may try "o.TransactionsRecord != null", but you would get struck
// by https://nhibernate.jira.com/browse/NH-3117 bug.
return q.Where(o => o.TransactionsRecord.TotalAmount != null);
I maintain my other answer since you may consider using a many-to-one instead, especially since you do not have made a bidirectionnal mapping (no corresponding constrained one-to-one in Wish) in addition to not having an actual one-to-one. many-to-one does not suffer of the bug.
one-to-one mapping using property-ref is not an "actual" one-to-one, and usually this is a sign a many-to-one mapping should be used instead.
Maybe this is not related to your trouble, but you may give it a try.
An "actual" one-to-one has the dependent table primary key equals to the parent table primary key. (Dependent table, Wish in your case, would have a foreign primary key, UserId in your case. See this example.)
I have sometime "played" with 'one-to-one property-ref', and I always ended giving it up due to many issues. I replaced that with more classical mappings, either changing my db for having an actual one-to-one, or using a many-to-one and living with a collection on child side though it would always contain a single element.
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">
<hibernate-mapping package="com.test.info">
<class name="LevelInfo">
<composite-id>
<key-property column="ID" name="id"/>
</composite-id>
<property column="NAME" name="name"/>
<property column="DESC" name="desc"/>
<bag name="details" cascade="all" order-by="ID" >
<key column="ID"/>
<one-to-many class="DeatilInfo"/>
<loader query-ref="includedDetailsSql"/>
</bag>
</class>
<sql-query name="includedDetailsSql" >
<load-collection alias="details" role="LevelInfo.details"/>
SELECT {details.*} FROM
DETAILS_TEMP detail
WHERE detail.ID = ?
AND detail.CODE=:myParam
</sql-query>
</hibernate-mapping>
The problem is that I want to pass parameter i.e myParam for filtering the records in the collection loading sql. Hibernate has passed the foreign key ID in the above query but I could not find a way to pass any other parameter in this query dynamically.
Further I also want to sort collection elements on a field that can be set dynamically. So is there any way to set order by attribute value in bag mapping dynamically.
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>
Consider these two classes mapped to the same table. One is readonly via mutable="false".
<class name="Funder" table="funder">
<id name="id">
<generator class="identity" />
</id>
<property name="funder_name" />
<property name="contact_name" />
<property name="addr_line_1" />
<property name="addr_line_2" />
<property name="addr_line_3" />
<property name="city" />
<many-to-one name="state" column="state_id" foreign-key="FK_funder_state_id" fetch="join" />
<property name="zip_code" length="10" />
<property name="phone_number" length="30" />
<property name="create_dt" update="false" not-null="true" />
<many-to-one name="create_by" column="create_by" not-null="true" update="false" foreign-key="FK_funder_create_by" fetch="join" />
<property name="last_update_dt" insert="false" />
<many-to-one name="last_update_by" insert="false" foreign-key="FK_funder_last_update_by" fetch="join" />
</class>
<class name="FunderSimple" table="funder" schema-action="none" mutable="false">
<id name="id">
<generator class="identity" />
</id>
<property name="funder_name" />
<property name="contact_name" />
<property name="phone_number" />
</class>
If I move the FunderSimple mapping before the Funder mapping my schema does not generate correctly. If I leave it as is above, it works.
Is this by design? It seems as though the schema-action="none" sticks to the table_name and later mappings to the same table will not generate the schema.
I'm doing it like this because I have another class named Contract which has a foreign key to the funder table. However, I don't need all the funder columns when referencing from the contract object.
<many-to-one name="funder_simple" column="funder_id" foreign-key="FK_contract_funder_id" fetch="join" />
Funder does not inherit from FunderSimple.
Should I be using a different technique to fetch only a subset of columns from a foreign key table? Is many-to-one the only way to setup a foreign key?
using version 2.1.0.4000
For such situations, I use projections instead.
I've never mapped two types to the same table (unless for inheritance reasons).
So, what I do in such a situation is:
create the FunderSimple class, and import it so that it is known by NHibernate:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<import class="MyNamespace.FunderSimple" />
</hibernate-mapping>
Once you've done this, you can create a query on your 'Funder' type, with the ICriteria API, but, you could specify that you would like NHibernate to return instances of FunderSimple.
By doing so, NHibernate is smart enough to generate a simplified SQL query, that only retrieves the columns that are necessary to populate instances of the FunderSimple class.
This is done like this:
ICriteria crit = session.CreateCriteria (typeof(Funder));
// add some expressions ...
crit.Add ( ... );
// Now, set the projection, and specify that FunderSimple should be returned
crit.SetProjection (Projections.ProjectionList()
.Add (Projections.Property ("Id"), "Id")
.Add (Projections.Property ("funder_name"), "funder_name")
.Add (Projections.Property ("phone_number"), "phone_number"));
crit.SetResultTransformer (Transformers.AliasToBean (typeof(FunderSimple)));
crit.List <FunderSimple>();