How to properly Update a Collection<Entity>? - spring-data-jpa

Here's what I tried:
public Collection<User> updateUsers(Collection<User> users) {
Collection<User> usersUpdated = null;
users.stream()
.filter(u -> userRepository.existsById(u.getId()))
.forEach(
u -> {
Optional<User> user = userRepository.findById(u.getId());
userRepository.save(user);
usersUpdated.add(userRepository.findById(u.getId()));
logger.debug("Update single " + User.class.getName() + ": " + u);
}
);
return usersUpdated;
}
The issue is on userRepository.save(user) where I'm getting the following:
Inferred type 'S' for type parameter 'S' is not within its bound; should extend 'com.example.model.User'
How should I properly update a collection of this entity?

You're getting the 'Inferred type not within its bound' exception, because you're passing an Optional to the save method, instead of a User object.
And I would suggest that you can save the entire collection with one request to the database, using CrudRepository.saveAll(), like this:
userRepository.saveAll(users);

Related

How to execute stored procedure in EF Core with return value TResult

I created an async method with TResult return type but I get error in return value.
I try to return a list value but I'm getting an error:
public async Task<IList<T>> ExecWithStoreProcedureGetListAsync<T>(string query, params object[] parameters)
{
query = "EXEC " + query + " ";
foreach (var item in parameters)
{
var cItem = (SqlParameter)item;
query = query + "#" + cItem.ParameterName + " " + (cItem.Direction == System.Data.ParameterDirection.Output ? "out" : "") + ",";
}
query = query.Substring(0, query.Length - 1);
return await this.context.Database.SqlQuery<T>(query, parameters).ToListAsync();
}
Error:
'DatabaseFacade' does not contain a definition for 'SqlQuery' and no accessible extension method 'SqlQuery' accepting a first argument of type 'DatabaseFacade' could be found (are you missing a using directive or an assembly reference?)
EF Core provides the following methods to execute a stored procedure:
DbSet.FromSql()
DbContext.Database.ExecuteSqlCommand()
Using FromSql
This method executes the stored procedure which returns entity data
using (var context = new SampleContext())
{
var authorId = new SqlParameter("#AuthorId", 1);
var books = context.Books
.FromSql("EXEC GetBooksByAuthor #AuthorId" , authorId)
.ToList();
}
Using ExecuteSqlCommand()
This method returns an integer specifying the number of rows affected by the SQL statement passed to it. Valid operations are INSERT, UPDATE and DELETE. The method is not used for returning entities
using(var context = new SampleContext())
{
var name = new SqlParameter("#CategoryName", "Test");
context.Database.ExecuteSqlCommand("EXEC AddCategory #CategoryName", name);
}
Reference :
https://www.learnentityframeworkcore.com/raw-sql#stored-procedures
https://learn.microsoft.com/en-us/ef/core/querying/raw-sql
https://www.entityframeworktutorial.net/efcore/working-with-stored-procedure-in-ef-core.aspx

What to do when SObject is not being found?

I am trying to empty the recycleBin. Thus I need to query the existing SObjects of the records. If a match of the records SObject Name has been found, than the query should happen. Else it just shouldn't query anything. The return type is a query.
How should I write the else part without having crashing problems when the SObject does not exists.
I thought of a try catch block where the try part would contain the
if(exists){query;}
and the catch part would just don't do anything, means it would be empty. Does that make sense?
What would you suggest?
Boolean exists = Schema.getGlobalDescribe().containsKey(sObjectName);
try {
if(exists){
return Database.getQueryLocator('SELECT Id FROM ' + sObjectName
+' WHERE isDeleted=true ALL ROWS');
}
}
catch (QueryException ex) {
// do nothing
}
Assuming you have a method which will return the Database.getQueryLocator
public Database.QueryLocator testMethod(String sObjectName )
{
return Database.getQueryLocator('SELECT Id FROM ' + sObjectName
+' WHERE isDeleted=true ALL ROWS');
}
Check if the sObject exists before calling the method.
Boolean exists = Schema.getGlobalDescribe().containsKey(sObjectName);
if(exists)
{
Database.QueryLocator ql = testMethod(String sObjectName);
}

How to retrieve subproperty of a data property in OWL API 4.0

I am using owl api 4.0 and the following code will give me all the property of individuals belonging to class Animal.
OWLClass animalCl = df.getOWLClass(IRI.create(ontologyIRI + "Animal"));
NodeSet<OWLNamedIndividual> animalIndl = reasoner.getInstances(animalCl, false);
for (OWLNamedIndividual animalNamedIndl : animalIndl.getFlattened())
{
Set<OWLDataPropertyAssertionAxiom> propAll= myontology.getDataPropertyAssertionAxioms(animalNamedIndl);
for (OWLDataPropertyAssertionAxiom ax: propAll)
{
for (OWLLiteral propertyLit : EntitySearcher.getDataPropertyValues(animalNamedIndl, ax.getProperty(), myontolgoy))
System.out.println("The property " + ax.getProperty() + "has value" + propertyLit);
}
}
I have a subproperty "propWt" for every data property. I have used following code:-
NodeSet<OWLDataProperty> properties = reasoner.getSubDataProperties((OWLDataProperty) ax.getProperty(), false);
for (OWLDataProperty mysubproperty : properties.getFlattened())
{
System.out.println("the sub property is " + mysubproperty);
}
instead of
the sub property is <http://localhost:3030/BiOnt.owl#propWt>
i get
the sub property is owl:bottomDataProperty
What is the problem here?
Since you are using a reasoner for the ontology, I assume you want all subproperties, either asserted or inferred.
The reasoner can do the job:
NodeSet<OWLDataProperty> properties = reasoner.getSubDataProperties(property, false);

can i use custom lambda method in entity framework?

i have some methods like:
public static string ToOtherFormat (this string inp)
{
// some code to change inp
return inp;
}
and in my select i want to have code like this:
var DetailMembers = db.TB_Members
.Where(x=> x.FName == obj.ToOtherFormat())
.Select( x=> new { name = (x.FName.ToOtherFormat() + " " + x.LName) , x.ActCode });
i try and just have error. is it possible?
thanks!
i receive this error in simple convert to integer
LINQ to Entities does not recognize the method 'Int32 ToInt32(System.String)' method, and this method cannot be translated into a store expression.
with this code
.Where(x => x.MemberID == Convert.ToInt32(Hmemid.Hash_two_Decrypt())
Looks like you are querying against the database. Your current query will get translated into SQL query and since SQL doesn't recognize your function that is why you get error.
You may get the data from the tables using a query without that function and then later do the formatting on the result set.
i found it on use .AsEnumerable() method like:
var DetailMembers = db.TB_Members.AsEnumerable()
.Where(x=> x.FName == obj.ToOtherFormat())
.Select( x=> new { name = (x.FName.ToOtherFormat() + " " + x.LName) , x.ActCode });

FunctionImport in entity framework 4 issue

I'm using entity framework 4.
I have a stored procedure that just updates one value in my table, namely the application state ID. So I created a stored procedure that looks like this:
ALTER PROCEDURE [dbo].[UpdateApplicationState]
(
#ApplicationID INT,
#ApplicationStateID INT
)
AS
BEGIN
UPDATE
[Application]
SET
ApplicationStateID = #ApplicationStateID
WHERE
ApplicationID = #ApplicationID;
END
I created a function import called UpdateApplicationState. I had initially set its return type to null, but then it wasn't created in the context. So I changed its return type to int. Now it was created in the context. Is it wise to return something from my stored procedure?
Here is my method in my ApplicationRepository class:
public void UpdateApplicationState(int applicationID, int applicationStateID)
{
var result = context.UpdateApplicationState(applicationID, applicationStateID);
}
Here is my calling code to this method in my view:
applicationRepository.UpdateApplicationState(id, newApplicationStateID);
When I run it then I get the following error:
The data reader returned by the store
data provider does not have enough
columns for the query requested.
Any idea/advise on what I can do to get this to work?
Thanks
To get POCO to work with function imports that return null, you can customize the .Context.tt file like this.
Find the "Function Imports" named region (the section that starts with region.Begin("Function Imports"); and ends with region.End();) in the .Context.tt file and replace that whole section with the following:
region.Begin("Function Imports");
foreach (EdmFunction edmFunction in container.FunctionImports)
{
var parameters = FunctionImportParameter.Create(edmFunction.Parameters, code, ef);
string paramList = String.Join(", ", parameters.Select(p => p.FunctionParameterType + " " + p.FunctionParameterName).ToArray());
var isReturnTypeVoid = edmFunction.ReturnParameter == null;
string returnTypeElement = String.Empty;
if (!isReturnTypeVoid)
returnTypeElement = code.Escape(ef.GetElementType(edmFunction.ReturnParameter.TypeUsage));
#>
<# if (isReturnTypeVoid) { #>
<#=Accessibility.ForMethod(edmFunction)#> void <#=code.Escape(edmFunction)#>(<#=paramList#>)
<# } else { #>
<#=Accessibility.ForMethod(edmFunction)#> ObjectResult<<#=returnTypeElement#>> <#=code.Escape(edmFunction)#>(<#=paramList#>)
<# } #>
{
<#
foreach (var parameter in parameters)
{
if (!parameter.NeedsLocalVariable)
{
continue;
}
#>
ObjectParameter <#=parameter.LocalVariableName#>;
if (<#=parameter.IsNullableOfT ? parameter.FunctionParameterName + ".HasValue" : parameter.FunctionParameterName + " != null"#>)
{
<#=parameter.LocalVariableName#> = new ObjectParameter("<#=parameter.EsqlParameterName#>", <#=parameter.FunctionParameterName#>);
}
else
{
<#=parameter.LocalVariableName#> = new ObjectParameter("<#=parameter.EsqlParameterName#>", typeof(<#=parameter.RawClrTypeName#>));
}
<#
}
#>
<# if (isReturnTypeVoid) { #>
base.ExecuteFunction("<#=edmFunction.Name#>"<#=code.StringBefore(", ", String.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray()))#>);
<# } else { #>
return base.ExecuteFunction<<#=returnTypeElement#>>("<#=edmFunction.Name#>"<#=code.StringBefore(", ", String.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray()))#>);
<# } #>
}
<#
}
region.End();
What I'm doing here is instead of ignoring all function imports that return null, I'm creating a method that returns null. I hope this is helpful.
It is because you do not actually returning anything from your stored procedure. Add a line like below to your SP (SELECT ##ROWCOUNT), and it will be executing properly.
BEGIN
...
SELECT ##ROWCOUNT
END
While this solution will address your issue and actually returns the number of effected rows by your SP, I am not clear on why this is an issue for you:
I had initially set its return type to null, but then it wasn't created in the context.
When doing a Function Import, you can select "None" as return type and it will generate a new method on your ObjectContext with a return type of int. This method basically executes a stored procedure that is defined in the data source; discards any results returned from the function; and returns the number of rows affected by the execution.
EDIT: Why a Function without return value is ignored in a POCO Scenario:
Drilling into ObjectContext T4 template file coming with ADO.NET C# POCO Entity Generator reveals why you cannot see your Function in your ObjectContext class: Simply it's ignored! They escape to the next iteration in the foreach loop that generates the functions.
The workaround for this is to change the T4 template to actually generate a method for Functions without return type or just returning something based on the first solution.
region.Begin("Function Imports");
foreach (EdmFunction edmFunction in container.FunctionImports)
{
var parameters = FunctionImportParameter.Create(edmFunction.Parameters, code, ef);
string paramList = String.Join(", ", parameters.Select(p => p.FunctionParameterType + " " + p.FunctionParameterName).ToArray());
// Here is why a Function without return value is ignored:
if (edmFunction.ReturnParameter == null)
{
continue;
}
string returnTypeElement = code.Escape(ef.GetElementType(edmFunction.ReturnParameter.TypeUsage));
...