I currently have an issue when updating a component collection on an entity. It was originally mapped as a bag but that was causing all entries to be deleted and reinserted each time. Changing it to a set has fixed that problem but introduced a new one.
The component type is called Tracking it has a composite key of UserID and ItemID and two properties which are nullable dates. When one of these is created DateRead set to the current time, it is then replaced later with an entry with the new date on.
The underlying SQL NHibernate generates has a where clause which checks that all properties match.
The issue is, the other date DateAcknowledged is often null, and the generated SQL seems to have a syntax error, to do a null check its doing this: = NULL rather than: IS NULL, as shown:
DELETE FROM TrackingTable
WHERE ItemId = 'a68f6dea-1c00-42e2-bc40-9fcf01121bd8' /* #p0 */
AND UserId = 'c8aa41a4-e4c2-4347-ae6e-b48738a53b47' /* #p1 */
AND DateRead = '2012-01-26T12:56:46.00' /* #p2 */
AND DateAcknowledged = NULL /* #p3 */
The thing is, the two dates should not be needed at all to determine what to delete. Simply having the where check item ID and user ID would do.
Here is the mapping code where I define the set:
Set(x => x.Trackings,
mapper =>
{
mapper.Key(k => k.Column("ItemId"));
mapper.Table("Tracking");
mapper.Access(Accessor.NoSetter);
},
collectionMapping => collectionMapping.Component(TrackingMap.Mapping()));
And here is the mapping for the component:
public class TrackingMap
{
public static Action<IComponentElementMapper<Tracking>> Mapping()
{
return c =>
{
c.ManyToOne(x => x.User, a => { a.Column("UserId"); a.ForeignKey("UserId"); });
c.Property(x => x.DateRead);
c.Property(x => x.DateAcknowledged, a => a.NotNullable(false));
};
}
}
Is there a way to tell NHibernate to use the keys only on the where clause or for it to compare nulls in the correct way?
This is covered by section 7.2. Collections of dependent objects which notes that this is not supported:
Please note that a composite element mapping doesn't support null-able properties if you're using a <set>. NHibernate has to use each columns value to identify a record when deleting objects (there is no separate primary key column in the composite element table), which is not possible with null values. You have to either use only not-null properties in a composite-element or choose a <list>, <map>, <bag> or <idbag>.
Please see this answer for a good explanation of how to delete NHibernate entities using criteria. This should allow you to use only ItemId and UserId when determining the items to delete and safely ignore the date comparisons.
Related
When I define a domain object like:
class MusicPlayed {
String user
Date date = new Date()
String mood
static mapping = {
id name: 'played_id'
version false
}
}
I get a postgres sequence automatically defined like:
CREATE SEQUENCE seq_music_played
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 1
CACHE 1;
That's great -- but I'd love to have this become the default value for my id field. In other words, I'd like to have the table defined with:
played_id bigint DEFAULT nextval('seq_music_played'::regclass) NOT NULL,
... but this doesn't happen. So when my client code requires manual SQL invocation, I'm stuck pulling new values form the sequence instead of just relying on auto-population.
Is there any way to cause this table to be created "the way I want," or do I need to forgo gorm's table-creation magic and just create the tables myself with a db-creation script that runs at install-time?
Note My question is similar to How to set up an insert to a grails created file with next sequence number?, but I'm specifically looking for a solution that doesn't pollute my client code.
This works for me :-)
static mapping = {
id generator: 'native', params: [sequence: 'my_seq'], defaultValue: "nextval('my_seq')"
}
Generating something like:
create table author (
id int8 default nextval('nsl_global_seq') not null,...
for postgresql.
I would use:
static mapping = {
id generator: 'native', params:[sequence:'your_seq']
}
Additionally, i would update the DEFAULT-Value of the id-column via
ALTER TABLE your_table ALTER COLUMN id SET DEFAULT nextval('your_seq');
This is extremely useful for manual INSERTs
UPDATE - use liquibase for the default-column-problem:
changeSet(author:'Bosh', id:'your_table_seq_defaults', failOnError: true) {
sql ("ALTER TABLE your_table ALTER COLUMN id SET DEFAULT nextval('your_seq')")
}
I tend to create my tables directly in PostgreSQL and then map them in grails.
I took the best idea to the sequences-generated-IDs from here:
http://blog.wolfman.com/articles/2009/11/11/using-postgresql-with-grails
Give it a try and then smile at your former problems :)
rawi
You can define it in Config.groovy
grails.gorm.default.mapping = {
id generator: 'sequence'
}
I have a LinQ query which is intended to Update the table concerned.
The code is as follows:
LINQHelperDataContext PersonalDetails = new LINQHelperDataContext();
var PerDetails1 = (from details in PersonalDetails.W_Details_Ts
where details.UserId == userId
select details).First();
PerDetails1.Side = "Bridge";
PerDetails1.TotalBudget = 4000000;
PersonalDetails.SubmitChanges();
However, this change/update does not get reflected in the DB. Also,this does not throw any exception.Please suggest.
Make sure W_Details_Ts has one (or more) member properties marked as primary key. L2S can't generate update or delete statements if it does not know the underlying table's PK member(s).
I have an NHibernate entity called Owner that has a SSN column and a TaxID column in the database, and I would like to conditionally map one of those two values to a more generic property on the Owner entity based on the value of a different property, StructureType. So, if the StructureType is "I", I want to map the SSN value to the generic property, and if its "C" I want to map the TaxID value to the generic property. Is this possible using Fluent NHibernate (or even regular NHibernate)? The Owner entity is a read-only entity, nothing will be written back to the database.
I was able to solve this using a Formula in Fluent NHibernate:
Map(x => x.Identification)
.Formula("CASE WHEN StructureType = 'I' THEN SSN ELSE TaxID END");
(In my original post I said it was between 'I' and 'C' but is in fact just between 'I' and every other type)
Why don't you add a readonly property?
public string Identification
{
get
{
string identification = string.Empty;
if (StructureType.Equals("I"))
identification = SSN;
else if (StructureType.Equals("C"))
identification = TaxID;
return identification;
}
}
Using: SQL Server 2008, WCF 4 REST, EF
I have an adjacency list table representing a tree
TABLE Category
(
CatId int IDENTITY(1,1) NOT NULL PRIMARY KEY,
ParentId int NULL,
Name nvarchar(50) NOT NULL
)
I am creating a WCF REST API to allow the client to build the tree in a lazy load way. Doing the query to get the children of a node (nodeid below) is straight-forward. What i'm running into is the need to identify which nodes are leaf nodes. (Note: I've removed all error handling, count = 0 handling, null handling, etc. from the code below)
tree = _context.Categories
.Where(c => c.ParentId == nodeid)
.Select(p => new TreeNode
{
id = p.CatId,
parentId = p.ParentId ?? -1, // -1 = NULL in data struct
name = p.Name,
isleaf = true // how to figure this out?
}).ToList();
Any ideas? I'm OK going to a stored proc for this query and have thought of using CTE, but i don't want to recurse through the entire tree - just get the children of the specified node.
EDIT (20 Jan, 10:40am)
I've decided to alter the DB Schema to add the "IsLeaf" bit column. I then did an update to set the IsLeaf accordingly - which means i don't have to dynamically figure it out at runtime. Probably more efficient, but I'm still curious how i would go about it. Please advise.
There is no recursive functions in LINQ (yet?). So while it's somewhat easy in MSSQL, in LINQ I'd suggest doing the following (pseudocode):
// These two lines is one LINQ statement
level = select all root nodes (ParentID == NULL)
add level nodes to result
// C# loop
while level is not empty
// The loop body except for the assignment in the end is one LINQ statement
next = select all nodes that have parentId in level
for each node in next
find parent node
add to result with updated parent info
// C# assignment
level = next
As you may see it's a combination of LINQ and C#. Also it may worth bringing the content of the table locally before doing all this.
Also you may need to update the algo to check for cycles if necessary.
I have some tables that represent various types. They usually just consist of an ID (int), and a name. Ideally I would have this in an enum. Is there a way to map a table like this onto an enum?
EDIT: How would I handle it if there were extra fields other than an ID and Name?
If it's just an id and a name, I generally do this:
public enum FootScent : int
{
Unknown = 0,
Mild = 1,
Sweaty =2,
SteppedInSomething = 3
}
and then on the LINQ entity property:
[Column("foot_scent_id", DbType = "Int NOT NULL")]
public FootScent Scent { get; set; }
For lookup tables with columns other than "id" and "name" that are needed, I usually just make a normal LINQ entity for them, though depending on your implementation it would probably be worth caching these to minimize trips to the DB.