How to retrieve generated fields such as generated id or updated_at field by a trigger during insert/update in springboot - postgresql

In postgres it's possible to retrieve computed values using returning. I have a generated id field and a field called updated_at that is updated by a trigger whenever a row is modified.
I'd like to achieve something like this but looks like it's not working. Not sure it's the right syntax for bulk insert.
#Query(value = "INSERT INTO entities VALUES :values RETURNING *",nativeQuery = true)
List<Entity> insertAndReturn(#Param("values") List<Entity> entities);
The error is:
java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing
I have also looked into jdbctemplate but it seems we are losing the benefit of entity mapping and we need to write own customized mapper.

That's not going to work. Native SQL doesn't support multi-valued parameters. You have to list all parameters individually. You can try something like this
default List<Entity> insertAndReturn(#Param("values") List<Entity> entities) {
for (int i = 0; i < entities.size(); i++ ) {
entities.set(i, insertAndReturn(entities.get(i)));
}
return entities;
}
default Entity insertAndReturn(Entity entity) {
return insertAndReturn(entity.getColumn1(), entity.getColumn2());
}
#Query(value = "INSERT INTO entities_table(column1, column2) VALUES (:column1, :column2) RETURNING *",nativeQuery = true)
Entity insertAndReturn(#Param("column1") String column1, #Param("column2") String column2);

Related

Not able to use IN query in LINQ with Entity Framework

I am using EF Framework to retrieve the data from SQL DB.
Sub Request Table looks like below:
In this table "org_assigneddept" is foreign key to another Department Table.
I have list of Departments as Input and I want to retrieve only those rows from DB whose org_assigneddept is matching the list.
Please find my whole code:-
private List<EventRequestDetailsViewModel> GetSummaryAssignedDeptEventRequests(List<EmpRoleDeptViewModel> vmDept)
{
List<EventRequestDetailsViewModel> vmEventRequestDeptSummary = new List<EventRequestDetailsViewModel>();
RequestBLL getRequestBLL = new RequestBLL();
Guid subRequestStatusId = getRequestBLL.GetRequestStatusId("Open");
using (var ctxGetEventRequestSumm = new STREAM_EMPLOYEEDBEntities())
{
vmEventRequestDeptSummary = (from ers in ctxGetEventRequestSumm.SubRequests
where vmDept.Any(dep=>dep.DeptId == ers.org_assigneddept)
select new EventRequestDetailsViewModel
{
SubRequestId = ers.org_subreqid
}).ToList();
}
}
It is giving the following error at the LINQ Query level:-
System.NotSupportedException: 'Unable to create a constant value of
type 'Application.Business.DLL.EmpRoleDeptViewModel'. Only primitive
types or enumeration types are supported in this context.'
Please let me know as how can I achieve the result
You cannot pass the department VMs to SQL, it doesn't know what those are.
// Extract the IDs from the view models.. Now a list of primitive types..
var departmentIds = vmDept.Select(x => x.DeptId).ToList();
then in your select statement...
..
where departmentIds.Contains(id=> id == ers.org_assigneddept)
..

Entity Framework Interceptor to set Id field of patricular entities

In my current project i am working with the database which has very strange table structure (All Id Fields in most tables are marked as not nullable and primary while there is not auto increment increment enabled for them those Id fields need to be unique as well).
unfortunately there is not way i can modify DB so i find another why to handle my problem.
I have no issues while querying for data but during insert What i want to do is,
To get max Id from table where entity is about to be inserted and increment it by one or even better use SSELECT max(id) pattern during insert.
I was hoping to use Interceptor inside EF to achieve this but is looks too difficult for me now and all i managed to do is to identify if this is insert command or not.
Can someone help me through my way on this problem? how can i achieve this and set ID s during insert either by selecting max ID or using SELECT max(id)
public void TreeCreated(DbCommandTreeInterceptionContext context)
{
if (context.OriginalResult.CommandTreeKind != DbCommandTreeKind.Insert && context.OriginalResult.DataSpace != DataSpace.CSSpace) return;
{
var insertCommand = context.Result as DbInsertCommandTree;
var property = insertCommand?.Target.VariableType.EdmType.MetadataProperties.FirstOrDefault(x => x.Name == "TableName");
if (property == null) return;
var tbaleName = property?.Value as ReadOnlyCollection<EdmMember>;
var variableReference = insertCommand.Target.VariableType.Variable(insertCommand.Target.VariableName);
var tenantProperty = variableReference.Property("ID");
var tenantSetClause = DbExpressionBuilder.SetClause(tenantProperty, DbExpression.FromString("(SELECT MAX(ID) FROM SOMEHOWGETTABLENAME)"));
var filteredSetClauses = insertCommand.SetClauses.Cast<DbSetClause>().Where(sc => ((DbPropertyExpression)sc.Property).Property.Name != "ID");
var finalSetClauses = new ReadOnlyCollection<DbModificationClause>(new List<DbModificationClause>(filteredSetClauses) { tenantSetClause });
var newInsertCommand = new DbInsertCommandTree(
insertCommand.MetadataWorkspace,
insertCommand.DataSpace,
insertCommand.Target,
finalSetClauses,
insertCommand.Returning);
context.Result = newInsertCommand;
}
}
Unfortunately that concept of Interceptor is a little bit new for me and i do not understand it completely.
UPDATE
I manage to dynamically build that expression so that ID field is now included in insert statement, but the problem here is that I can not use SQL query inside it. whenever i try to use this it always results in some wrong SQL query so is there anyway i tweak insert statement so that this SELECT MAX(ID) FROM TABLE_NAME is executed during insert?
Get the next id from the context, and then set the parameter of the insert command accordingly.
void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
var context = interceptionContext.DbContexts.First() as WhateverYourEntityContainerNameIs;
// get the next id from the database using the context
var theNextId = (from foo in context...)
// update the parameter on the command
command.Parameters["YourIdField"].Value = theNextId;
}
Just bear in mind this is not terribly thread safe; if two users update the same table at exactly the same time, they could theoretically get the same id. This is going to be a problem no matter what update method you use if you manage keys in the application instead of the database. But it looks like that decision is out of your hands.
If this is going to be a problem, you might have to do something more drastic like alter the command.CommandText to replace the value in the values clause with a subquery, for example change
insert into ... values (#YourIdField, ...)
to
insert into ... values ((select max(id) from...), ...)

Hydrate non required string properties from null to empty string

If I have a model class
public class Foo
{
public string Property1 { get; set; } = string.Empty;
... other properties omitted for brevity
}
It gets save to the database as null since it is not a required property. But now when I retrieve the entity that property is null.
I have a lot of not required string properties on this entity and I don't want to have to do a lot of null checking on those properties, I just want them to be rehydrated as empty strings if they are null in the database. I don't mind them being stored in the db as null but when the entity is retrieved from the db I would like to have it mapped back to empty string if it is null in the db.
I'm thinking this must be a fairly common scenario and was wondering if I'm missing some simple way to do it with a configuration setting or something. I am fairly new to using EF.
In my OnModelCreating for this property I have:
.HasMaxLength(50)
.HasDefaultValue(string.Empty)
but it still gets stored as null and rehydrated as null. Again I don't mind it being stored as null but I want it hydrated as empty string if it is null in the db.
I tried modifying the model class like this:
private string property1 = string.empty;
public string Property1
{
get { return property1; }
set { property1 = value ?? string.Empty; }
}
thinking that EF must have to use the setter but this still resulted in a null property. So far the only way I've been able to solve it by making the property like this:
private string property1 = string.empty;
public string Property1
{
get { return property1 ?? string.empty; }
set { property1 = value ?? string.Empty; }
}
I'd really rather not have to make all my properties like that.
Can anyone suggest a cleaner way to do this or correct me if I'm doing something wrong or unusual or thinking about it wrong. Am I missing some easier way to achieve this?
I don't want to make the property required since empty string would not satisfy that case either.
The question's original Entity Framework version was EF7, the first ef-core version that was renamed to EF-core 1 later. The described behavior considerably differs from the current EF-core version (2.1.1).
Let me mention the two key points:
1
It gets save to the database as null since it is not a required property. But now when I retrieve the entity that property is null.
That's not what happens currently.
Take a simple class:
public class Item
{
public int ID { get; set; }
public string Name { get; set; }
public string Code { get; set; } = string.Empty;
}
When adding an Item of which only Name is set, the following SQL is executed:
exec sp_executesql N'SET NOCOUNT ON;
INSERT INTO [Items] ([Code], [Name])
VALUES (#p0, #p1);
SELECT [ID]
FROM [Items]
WHERE ##ROWCOUNT = 1 AND [ID] = scope_identity();
',N'#p0 nvarchar(4000),#p1 nvarchar(50)',#p0=N'',#p1=N'Item1'
The empty string is part of the insert statement. Also, when retrieving the item from the database, its Code is an empty string.
2
In my OnModelCreating for this property I have:
.HasMaxLength(50)
.HasDefaultValue(string.Empty)
but it still gets stored as null and rehydrated as null.
That, too, is different now. Take the same class but now with:
public string Code { get; set; } // removed "= string.Empty;"
...and mapping for Code:
modelBuilder.Entity<Item>().Property(p => p.Code).HasMaxLength(50).HasDefaultValue(string.Empty);
...then this is the resulting table:
CREATE TABLE [Items] (
[ID] int NOT NULL IDENTITY,
[Name] nvarchar(50) NOT NULL,
[Code] nvarchar(50) NULL DEFAULT N'', -- Default constraint
CONSTRAINT [PK_Items] PRIMARY KEY ([ID])
);
As you see, the mapping instruction is translated into a database default.
When adding an Item of which only Name is set, the following SQL is executed:
exec sp_executesql N'SET NOCOUNT ON;
INSERT INTO [Items] ([Name])
VALUES (#p0);
SELECT [ID], [Code]
FROM [Items]
WHERE ##ROWCOUNT = 1 AND [ID] = scope_identity();
',N'#p0 nvarchar(50)',#p0=N'Item1'
So EF inserts the item and reads back the generated default value in order to keep the tracked entity in sync with the database. Likewise, an item read from the database later has an empty string in Code.
These findings confirm that EF7 was a very immature version of EF-core (although I didn't confirm that it really displayed the described behavior). There have been more, and more profound, breaking changes since it. I hope we will soon forget about these early EF-core versions. Since version 2.0, EF-core is finally developing into a production-ready ORM.

named native query and mapping columns to field of entity that doesn't exist in table

I have a named native query and I am trying to map it to the return results of the named native query. There is a field that I want to add to my entity that doesn't exist in the table, but it will exist in the return result of the query. I guess this would be the same with a stored proc...
How do you map the return results of a stored proc in JPA?...
How do you even call a stored proc?
here is an example query of what I would like to do...
select d.list_id as LIST_ID, 0 as Parent_ID, d.description from EPCD13.distribution_list d
The Result will be mapped to this entity...
public class DistributionList implements Serializable {
#Id
#Column(name="LIST_ID")
private long listId;
private String description;
private String owner;
private String flag;
#Column(name="PARENT_ID", nullable = true)
private long parentID;
}
parent ID is not in any table in my database. I will also need to use this entity again for other calls, that have nothing to do with this call, and that will not need this parent_id? Is there anything in the JPA standard that will help me out?
If results from database are not required for further manipulation, just for preview, you can consider using database view or result classes constructor expression.
If entities retrieved from database are required for further manipulation, you can make use of multiple select expression and transient fields.
Replace #Column annotation with #Transient annotation over parentID.
After retrieving multiple columns from database, iterate over results and manually set parentID.

Used 'new' operator in LINQ to SQL query, but same instance is referenced in every result

Can anyone explain the behavior I am seeing in the minimal code example below? It seems that for a given field or property, the same two instances of the Entry class are being reused in each iteration of the LINQ to SQL query, even though I use the new operator. The same problem does not show up for LINQ to objects queries. I created a C# console application project using .NET Framework 4 and connecting to a SQL Server 2005 Enterprise database.
public class Set
{
public Entry Field;
public Entry Property { get; set; }
}
public class Entry
{
public int ID;
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
var dc = new DataClasses1DataContext(); // just create a simple dbml with some table from some database
var resultQuery = (
from x in dc.SomeTable
select new Set()
{
Field = new Entry(),
Property = new Entry()
}
);
var sets = resultQuery.ToArray();
Test(sets);
var source = Enumerable.Range(0, 10);
var sourceQuery = (
from x in source
select new Set()
{
Field = new Entry(),
Property = new Entry()
}
);
var sets2 = sourceQuery.ToArray();
Test(sets2);
}
static void Test(Set[] sets)
{
var f = sets[0].Field;
Console.WriteLine(sets.All(x => object.Equals(x.Field, f)));
var p = sets[0].Property;
Console.WriteLine(sets.All(x => object.Equals(x.Property, p)));
Console.Writeline(sets.Length);
Console.WriteLine(object.Equals(f, p));
Console.WriteLine();
}
}
The output of Test() for the LINQ to SQL query is
True
True
1362
False
which indicates that for all of the Set objects produced, all the Field members point to the same single Entry instance and all the Property members point to the same single Entry instance. I.e., the same instance is reused for a respective member in every iteration of the query.
The output of Test() for the LINQ to objects query is
False
False
10
False
which indicates that a new distinct instance is created in each iteration of the query.
Is the LINQ to SQL behavior expected or a bug? Does anyone know if this happens with the Entity Framework?
I don't know if this is a bug or if and why this is expected in LINQ to SQL. I can only answer your last question if that also happens with Entity Framework.
The answer is: No.
With EF you have to use object initializer syntax though when you instantiate the Entry objects. Using the default constructor leads to an exception:
var resultQuery = (
from x in dc.SomeTable
select new Set
{
Field = new Entry { Name = "X" },
Property = new Entry { Name = "X" }
}
);
It doesn't matter how you initialize. Using the code above (and with 4 rows in a small test table) I get this output with your test program:
False
False
4
False
False
False
10
False
It looks that there is a big difference between LINQ to SQL and Entity Framework regarding object materialization during projections.
(I've tested with EF 4.1/DbContext.)
Edit
If I take the modified query in my code snippet above also for your LINQ to SQL query and watch the generated SQL I get the following:
SELECT NULL AS [EMPTY]
FROM [dbo].[SomeTable] AS [t0]
Whereas the same with LINQ to Entites creates this query:
SELECT
1 AS [C1],
N'X' AS [C2],
N'X' AS [C3]
FROM [dbo].[SomeTable] AS [Extent1]
My interpretation is that LINQ to SQL parses the projection code and queries only columns for property values which depend on the "row variable" x. All other properties are filled on the client when the objects get materialized. If an object does not depend on a column value at all, LINQ to SQL creates a single constant object and reuses it in the whole result collection.
In constrast to this Entity Framework also sends constant values (independent of x) to the database server. The values get send back to the client and EF treats those values as if they were column values and updates the properties of the objects in the projection.
This leads also to the big difference that something like this...
Random random = new Random();
var resultQuery = (
from x in dc.SomeTable
select new Set
{
Field = new Entry { ID = random.Next() },
Property = new Entry { Name = "X" }
}
);
...works in LINQ to SQL because apparently the random function value (which is independent of x) is evaluated on the client and then assigned to the property. But EF wants to translate the right side of the property assignment into SQL and send it as SQL fragment to the database server - which fails and leads to the infamous "...cannot translate into store expression..." exception.
Edit 2
BTW: The last code snippet above still creates only a single Field instance in the whole collection: random.Next() is only evaluated once (and also the constructor of Entry is only called once for the Field object). This now is indeed confusing because writing such code one would expect that you want to have a random value for each row returned from the database. It's not the case.