ORM issue after upgrading to ColdFusion 2018 from version 11 - orm

We migrated from ColdFusion 11 to ColdFusion 2018 and now ORM is breaking the EntitySave method and we are getting below error message.
Error Message - The root cause of this exception was: coldfusion.orm.hibernate.HibernateSessionException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1.
We have 2 classes with one-to-many relationship like Email.cfc (parent) and EmailItems.cfc (child). When we try to save Email.cfc object the hibernate creates an UPDATE query for EmailItems as well and this is happening with ColdFusion 2018 only.
Here is the defined property in Email.cfc.
<cfproperty name="EmailItems"
lazy="true"
fieldtype="one-to-many"
inverse="true"
fkcolumn="EmailID"
cfc="EmailItem"
singularName="EmailItem"
type="struct"
structkeycolumn="EmailItemKey"
structkeytype="string"
cascade="none"
/>
We are using inverse and it still create an UPDATE query for child class 'EmailItems' which is the reason for failing EntitySave(Email). Everything works fine with ColdFusion 11.

Finally, I found the fix for this. It seems the inverse="true" properties doesn't work the same WITH cf2018 as it is working with CF2011.
After doing some research found that, by default a cascade property is added in <cfproperty> tag for one-to-many relationship whose value is UPDATE that means for any orphaned child object it is trying to update while this object doesn't exist at database level.
So, when adding cascade="save-update" in my <cfproperty> tag for on-to-many relationship, it fixes the problem because now it tries to INSERT instead of UPDATE for any orphaned child object.

Related

Coldfusion ORM Macromedia][Oracle JDBC Driver][Oracle]ORA-02289: sequence does not exist

I have a ColdFusion ORM application that uses an oracle sequence as the generator for the primary key field. I have verified that I can access the sequence as the user that ColdFusion is connected to the database as in SQL navigator.
My problem is I am getting the following error when I attempt to saveEntity() on any object
Root cause :java.sql.SQLException: [Macromedia][Oracle JDBC Driver][Oracle]ORA-02289: sequence does not exist
I have tried the syntax below with and without the akc. prefix. I do have the akc schema defined in the CFC
<cfproperty name="KEY_BREED_PAGE" fieldtype="id" generator="sequence" params="{sequence='akc.seq_breed_page_display'}" />
and
<cfproperty name="KEY_BREED_PAGE" fieldtype="id" generator="sequence" sequence="akc.seq_breed_page_display" />
Any ideas on what I can do to resolve this? The ORM works fine when updating but fails on every attempt to create a new record.
I had a similar when I didn't have the schema. The only difference between your example and mine is that I have the column attribute set.
<cfproperty name="KEY_BREED_PAGE" fieldtype="id" column="KEY_BREED_PAGE" generator="sequence" sequence="akc.seq_breed_page_display" />

NHibernate setting access="field.camelcase-underscore" fails in version 3

I have a solution that was created with NHib 1.2 which we're upgrading to NHib 3.0.
Our hbm file has the following property:
<property name="ContentId" column="ContentId" access="field.camelcase-underscore" />
The class doesn't have a ContentId property. This was working fine in NHib 1.2 but now we're getting getting the following exception:
Could not compile the mapping document: XXXX.Core.Domain.Video.hbm.xml ---> NHibernate.MappingException: Problem trying to set property type by reflection ---> NHibernate.MappingException: class Core.Domain.Video, Core, Version=1.0.0.29283, Culture=neutral, PublicKeyToken=null not found while looking for property: ContentId ---> NHibernate.PropertyNotFoundException: Could not find the property 'ContentId', associated to the field '_contentId', in class 'Core.Domain.Video'.
Why would this stop working? Is it still supported in NHib 3?
We have many many properties like this that we might need to add.
NHibernate greatly improved its error messaging and diagnostics in NH2.X and again in NH3.X. You are telling NHibernate that you have a property and you want to map it via field access to a field named by _camelCase convention. You don't have a property named ContentId and NHibernate is letting you know that you lied to it. :)
Try updating your mapping to:
<property name="_contentId" column="ContentId" access="field" />
You will need to update any HQL or Criteria queries to use _contentId rather than ContentId. Another option would be to add a private ContentId property.
I'd like to provide information which helped me answer this question:
http://groups.google.com/group/nhusers/browse_thread/thread/e078734a221c3c0c/ec8b873b385d4426?lnk=gst&q=field+camelcase+underscore#ec8b873b385d4426
In this link Fabio explains the same problem you are having like this:
This mapping
<property name="PositiveValue" access="field.camelcase-underscore" />
mean: For my property named "PositiveValue" you (NH) have to access to
the field; to discover which is the associated field you (NH) have to
use the strategy "camelcase-underscore".
If there is no property you can't use the accessor with a specific
strategy.
Which struck me as a little odd because it meant adding dummy, unused properties, just to make the nhibernate3 compiler happy. The underlying functionality is the same.

Entity Framework SaveChanges - how to ignore ID / Identity fields on INSERT

VB .NET 4 WinForms application.
I have a (DevExpress) grid bound to an IEnumerable(Of MyClass).
Whenever a new row is added, the ID defaults to zero (0). On trying to SaveChanges, EntityFramework doesn't realise that being an identity field means it should ignore any contents on insert and just insert the other values. I can't specify null / Nothing because it just keeps the ID as zero.
I can add and save instances of MyClass manually, but I'm trying to get it to work where the grid handles adding/initialising/etc new entries. As far as I can tell, the problem is not with the grid but with Entity Framework and the generated SQL and entity classes.
{"Cannot insert explicit value for identity column in table 'MyClasses' when IDENTITY_INSERT is set to OFF."}
Any assistance to prevent me from throwing my laptop out a window would be greatly appreciated!
If a property of an Entity is an Identity (auto-incrementing value) in the database is specified in the StorageModel of your Entity Model. Perhaps this setting is not correct for your particular field. You can check this by opening the edmx file of your model and looking into the StorageModels section. It should look like this:
<edmx:StorageModels>
...
<EntityType Name="MyClass">
<Key>
<PropertyRef Name="ID" />
</Key>
<Property Name="ID" Type="..." Nullable="..." StoreGeneratedPattern="Identity" />
...
</EntityType>
...
</edmx:StorageModels>
StoreGeneratedPattern must be set to Identity. If there is None or the attribute is missing (which defaults to None) you get indeed the error you described since EntityFramework doesn't know in this case that ID is an identity and will issue a value for the column in the generated SQL-INSERT statement.
(Make sure you are really checking the edmx:StorageModels section in the edmx file. The edmx:ConceptualModels section has an attribute annotation:StoreGeneratedPattern in the property as well but its setting doesn't matter for your specific problem. (I think that's only important when a database gets created from a model, but I'm not sure.))

NHibernate Parent/Child Orphaned Records with Web Service

I have a web service that accepts an Invoice, which contains LineItem children. It then updates the database to either create or update the Invoice using NHibernate.
When an invoice is updated, it is passed to the web service along with all LineItem children it now has. Adds and updates work perfectly. However, if a child LineItem is deleted from a previously persisted Invoice by the Web Service consumer and re-submitted, that LineItem is not actually removed from the database, but rather it's back reference to the parent is set to NULL. I am using (trying to use) cascade="all-delete-orphan" without success.
I suspect that the problem might be due to the stateless nature of the operation (I don't first have the LineItem in Invoice.LineItemList on the web service side and then delete it, but rather just get a list of LineItem's as they now should be). However, NHibernate IS smart enough to null the back-reference column, so I hope there's a straightforward way to get it to delete that row instead.
Here are the mappings (simplified).
Parent object (Invoice):
<property name="InvoiceNumber" />
<!-- If inverse="true", InvoiceId is NOT set to NULL and the record remains -->
<bag name="LineItemList" table="lineitems" inverse="false" cascade="all-delete-orphan">
<key column="InvoiceId"/>
<one-to-many
class="LineItem"/>
</bag>
Child Objects (LineItems):
<many-to-one lazy="false" name="Parent" column="InvoiceID" not-null="false"
class="Invoice,Company.Business"
/>
<property name="LineItemNumber" />
<property name="SalesAmount"/>
The Web Service persistence code looks like this:
[WebMethod]
public Invoice PutInvoice(Invoice invoice)
{
// Necessary to rebuild parent references, see Blog
foreach (LineItem item in invoice.LineItems)
{
item.Parent = invoice;
}
using (PersistenceManager pm = new PersistenceManager())
{
pm.Save<Invoice>(invoice);
}
return invoice; // Return version potentially modified with DB-assigned ID
}
You are right this has to to with the detached state of your objects and is a known limitation in admission to performance which NHibernate describes as the not implemented feature of 'persistence of reachability'. However you could of course easily delete all LineItems without valid invoice reference but i also don't like this solution.
Usually i use client objects to achieve statelessness which of course results in loading the invoice before manipulating.

Fluent NHibernate HasMany not updating the FK

I'm using latest Fluent NHibernate lib (0.1.0.452) and I have a problem with saving child entitites.
I think this is rather common scenario... I've got a parent with mapping:
HasMany<Packet>(x => x.Packets)
.Cascade.All()
.KeyColumnNames.Add("OrderId");
and a simple Packet class that (in a domain model and FNH mapping) doesn't have any reference to the parent.
What gets generated is a correct Packets table that contains a column named OrderId.
What doesn't work is the saving.
Whenever I try to save parent object, the children are also saved, but the FK stays untouched.
I checked the SQL and in INSERT statement the OrderId doesn't even appear!
INSERT INTO KolporterOrders (CargoDescription, SendDate, [more cols omitted] ) VALUES ('order no. 49', '2009-04-22 00:57:44', [more values omitted])
SELECT LAST_INSERT_ID()
INSERT INTO Packets (Weight, Width, Height, Depth) VALUES ('To5Kg', 1, 1, 1)
SELECT LAST_INSERT_ID()
As you see the OrderId is completely missing in the last INSERT.
I also checked the generated NH mapping and it seems it's ok:
<bag name="Packets" cascade="all">
<key column="OrderId" />
<one-to-many class="Company.Product.Core.Packet, Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</bag>
I tried setting Cascade to different values. I even added References to the PacketMap (FNH mapping class).
Any ideas why the OrderId is not being inserted?
Edit: forgot to mention: I'm using MySQL5 if it matters.
Edit2: The above FNH mapping generates hbm with bag (not a set) - I edited it.
The C# code used for saving:
var order = new Order();
NHSession.Current.SaveOrUpdate(order); //yes, order.Packets.Count == 1 here
///Order.cs, Order ctor
public Order()
{
CreateDate = DateTime.Now;
OrderState = KolporterOrderState.New;
Packets = new List<Packet>();
Packets.Add(new Packet()
{
Depth = 1,
Height = 1,
Width = 1,
Weight = PacketWeight.To5Kg
});
}
the session gets flushed and closed at EndRequest.
Ok, my fault. I was testing it in ApplicationStart of global.asax, so the Request hadn't been created so the session wasn't flushed. I realised it when I tested it on a simple ConsoleApp project when I saw that flushing actualy causes the FK col update.
Anyway: thanks for help!
In a "vanilla" parent-children object model, you must update the child's object's reference to the parent in order to cause NHibernate to update the child record's reference to the parent.
In an "inverted" parent-children object model, you must modify the parent's collection of children objects in order to cause NHibernate to update the child records' references to the parent.
It seems you may want to be using an "inverted" parent-children object model.
In the XML mapping, you need
<set name="Packets" cascade="all" inverse="true">
<key column="OrderId" />
<one-to-many class="Company.Product.Core.Packet, Core,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</set>
In the Fluent mapping, you need
HasMany<Packet>(x => x.Packets)
.Cascade.All()
.Inverse()
.KeyColumnNames.Add("OrderId")
;
This is really strange. You should check subsequent Updates, NHibernate sometimes updates foreign keys afterwards, and then it doesn't appear in the insert.
Make sure that OrderId does not have several meanings on the Packets table. To check this, change the name of OrderId to something else.
Cascading has nothing to do with it. It only controls if you need to save the child explicitly.