no instance of variable R exists so that void conforms to R - java-8

I have requirement to format user identifier with dept and date as below. But I get error as "no instance of variable R exists so that void conforms to R" when using map function
public List<Users> formatUserIdentifier(String dept, String joinDate) {
users.stream().map(user -> {
return user.setIdentifier(user.getIdentifier() + "_" + dept + "_" + joinDate);
});
return users;
}
Eg: Prior format, user = john
After format, user = john_CS_20210921
If I use forEach loop it works well. Can someone advise how to use map here, please?

I would recommend doing it with a forEach loop or regular for loop. In this case, you don't need to return anything so the return type would be void.
public void formatUserIdentifier(String dept, String joinDate) {
users.stream().forEach(user->
user.setIdentifier(user.getIdentifier() + "_" + dept + "_" + joinDate));
}
}
But here is how you might do it with map. You must create a new instance of the User class with the appropriate arguments. Those arguments must be the same from the current user class being processed in the stream. So each newly created User instance will be just like the one processed except for the identifier change.
public List<User> formatUserIdentifier(String dept, String joinDate) {
return user.stream()
.map(user-> new User(user.getIdentifier() + "_" + dept + "_" + joinDate,
other user arguments here ...))
.toList();
}

Related

Spring JDBC : Inconsistent results when performing Order By

Any help would be greatly appreciated. I am working on a project using Spring JDBC for data access and am performing a simple query with an order by column expression, I am currently getting inconsistent results meaning the order by doesn't seem to be working. I have tried more than one database still no avail.
String sql = "select * from account where upper(name) like upper(:query) order by name asc";
MapSqlParameterSource params = new MapSqlParameterSource().addValue("query", "%" + query + "%");
List<Account> accountsSearched = namedParameterJdbcTemplate.query(sql, params, new BeanPropertyRowMapper<Account>(Account.class));
Any ideas what could be the issue?
So the problem is not within your SQL code, but problem exist in search method implementation
Existing Code
public List<Account> search(String uncleanedQuery, int offset) {
String query = uncleanedQuery.replaceAll("([-+.^:,])","");
String sql = "select * from account where upper(name) like upper(:query) order by name asc";
MapSqlParameterSource params = new MapSqlParameterSource().addValue("query", "%" + query + "%");
List<Account> accountsSearched = namedParameterJdbcTemplate.query(sql, params, new BeanPropertyRowMapper<Account>(Account.class));
Set<Account> accountSearchSet = new HashSet<Account>(accountsSearched);
List<Account> accounts = new ArrayList<Account>(accountSearchSet);
return accounts;
}
In the above code, we are fetching data correctly but assigning it to HashSet. HashSet does not respect ordering by name and generates random order for Account, due to which you are getting random order every time.
Solution 1:
There is no reason, you actually need Set. Using set just making your program slow. If you want to get DISTINCT data then modify SQL query.
public List<Account> search(String uncleanedQuery, int offset) {
String query = uncleanedQuery.replaceAll("([-+.^:,])","");
String sql = "select * from account where upper(name) like upper(:query) order by name asc";
MapSqlParameterSource params = new MapSqlParameterSource().addValue("query", "%" + query + "%");
List<Account> accountsSearched = namedParameterJdbcTemplate.query(sql, params, new BeanPropertyRowMapper<Account>(Account.class));
return accountsSearched;
}
Solution 2:
Still, you want to go with your approach then change code to use TreeSet and order based on the name
public List<Account> search(String uncleanedQuery, int offset) {
String query = uncleanedQuery.replaceAll("([-+.^:,])", "");
System.out.println("Search Query Called");
String sql = "select * from account where upper(name) like upper(:query) order by name";
MapSqlParameterSource params = new MapSqlParameterSource().addValue("query", "%" + query + "%");
List<Account> accountsSearched = namedParameterJdbcTemplate.query(sql, params,
new BeanPropertyRowMapper<Account>(Account.class));
Comparator<Account> comp = new Comparator<Account>() {
#Override
public int compare(Account a1, Account a2) {
return a1.getName().compareTo(a2.getName());
}
};
SortedSet<Account> accountSearchSet = new TreeSet<Account>(comp);
accountSearchSet.addAll(accountsSearched);
List<Account> accounts = new ArrayList<Account>(accountSearchSet);
return accounts;
}

spring data jpa custom query fails to recognize class type

Not able to use custom POJO classes for my spring data jpa queries. Repeatedly fails with the following exception
"org.hibernate.MappingException: Unknown entity:
com.app.mycompany.AgileCenterServices.entities.ComponentDetailedInfo"*
Tried replacing the custom ComponentDetailedInfo.class and not mentioning anything during the call to entityManager.createNativeQuery(componentQuery.toString()), but then Object List returned fails to be converted to the specific POJO class after the query.
#Override
public ComponentListResponsePaginated findComponentByProjectId(String projectId, Pageable pageable) {
logger.info(" Inside findComponentByProjectId() API in IssueComponentServiceImpl");
String componentQuery = "select c.*, u.fullname "
+ "from issue_component c "
+ "left join user u on c.component_lead = u.username "
+ "where "
+ "upper(c.project_id) = upper(" + projectId + ")";
List<ComponentDetailedInfo> compList = new ArrayList<ComponentDetailedInfo>();
try {
logger.info(" ************* Printing query ******************************* ");
logger.info(componentQuery.toString());
compList = entityManager.createNativeQuery(componentQuery.toString(), ComponentDetailedInfo.class) .setFirstResult(pageable.getOffset())
.setMaxResults(pageable.getPageSize())
.getResultList();
}
}
Also tried the following
List<? extends Object> objList = null;
objList = entityManager.createNativeQuery(componentQuery.toString()) .setFirstResult(pageable.getOffset())
.setMaxResults(pageable.getPageSize())
.getResultList();
if(objList != null && objList.size() > 0) {
for(Object rec: objList) {
logger.info(" Printing Object ::: " + rec.toString());
compList.add((ComponentDetailedInfo)rec);
}
}
However the compList fails with the
java.lang.ClassCastException
The custom query returned should get typecast to the specific class type passed to the entityManager.createNativeQuery. However, I am facing the exception as mentioned above when I pass the class to createNativeQuery().
Even tried by totally removed the class in the createNativeQuery...
You have to define a constructor result mapping if you want to use a POJO as a result of a native query.
Here is an example query:
Query q = em.createNativeQuery(
"SELECT c.id, c.name, COUNT(o) as orderCount, AVG(o.price) AS avgOrder " +
"FROM Customer c " +
"JOIN Orders o ON o.cid = c.id " +
"GROUP BY c.id, c.name",
"CustomerDetailsResult");
And that's the mapping you have to add to your Entity:
#SqlResultSetMapping(name="CustomerDetailsResult",
classes={
#ConstructorResult(targetClass=com.acme.CustomerDetails.class,
columns={
#ColumnResult(name="id"),
#ColumnResult(name="name"),
#ColumnResult(name="orderCount"),
#ColumnResult(name="avgOrder", type=Double.class)})
})
If you don't like that approach you could use QLRM. Learn more about it here: https://github.com/simasch/qlrm

Searching through NHibernate

I have a search code which searches using three parameters but i want to pass a single parameter and match it with all three or four or any number of variables in the code.Can any one show me the way forward
ICriteria oCriteria = base.Session.CreateCriteria<Patient>("p").CreateCriteria("User", "u", NHibernate.SqlCommand.JoinType.InnerJoin)
.Add(Restrictions.Eq("u.IsDeleted", false)).Add(Restrictions.Eq("u.IsPatientSignUp", false)).Add(Restrictions.Like("u.FirstName", '%' + data + "%"))
.Add(Restrictions.Like("u.LastName", '%' + data + "%")).Add(Restrictions.Like("u.Email", '%' + data + "%"))
.Add(Restrictions.Or(cr1, cr2))
.AddOrder(Order.Asc(Projections.Cast(NHibernateUtil.Int32, Projections.Property("p.MedNexusId"))));
patient = oCriteria.List<Patient>().Skip(pageNumber * pageSize).Take(pageSize).ToList();
NHibernate gives us a set of basic tools (Restrictions in this case) and we can either extend them (create new ICriterion) or combine them. So we can create common methods like these:
// multiple AND
public static AbstractCriterion AllLike(IEnumerable<string> properties, string toCompare)
{
Conjunction conjunction = Restrictions.Conjunction();
foreach (var name in properties)
{
conjunction.Add(Restrictions.Like(name, toCompare, MatchMode.Anywhere));
}
return conjunction;
}
// multiple OR
public static AbstractCriterion AnyLike(IEnumerable<string> properties, string toCompare)
{
Disjunction disjunction = Restrictions.Disjunction();
foreach (var name in properties)
{
disjunction.Add(Restrictions.Like(name, toCompare, MatchMode.Anywhere));
}
return disjunction;
}
And now we can call them like:
ICriteria oCriteria = ....
var toMatch = new[] {"u.LastName", "u.Email", ...};
criteria.Add(AllLike(toMatch, data));
// or
criteria.Add(AnyLike(toMatch, data));
NOTE: the similar implementation is already there Restrictions.AllEq(IDictionary propertyNameValues)

Linq get all fields from select along with dynamic column

I have such Linq, I would like to get all records from Orders table and also add new dynamic field. The code below do not work. What is correct syntax?
user.dcOrders.Select(p =>p, new { FullName = p.FirstName + " " + p.LastName })
You'll need to list out all the columns.
Alternatively you could add a new property to whatever class dcOrders is. It should be specified as a partial class so you can add the FullName property to a new file so it doesn't get overwritten when the .designer.cs file is regenerated.
So something like
public partial class Orders
{
public string FullName { get { return this.FirstName + " " + this.LastName; } }
}
Be sure to add this to a separate file not the .designer.cs file. (I'm assuming LINQ to SQL here).
Then you don't need to do any special select, because FullName will already exist as a property on the object. You can just use it directly.
Try this:
var names = user.dcOrders.Select(p => new {
User = p,
FullName = p.FirstName + " " + p.LastName
});

Full Text Search in Linq

There's no full text search built into Linq and there don't seem to be many posts on the subject so I had a play around and came up with this method for my utlity class:
public static IEnumerable<TSource> GenericFullTextSearch<TSource>(string text, MyDataContext context)
{
//Find LINQ Table attribute
object[] info = typeof(TSource).GetCustomAttributes(typeof(System.Data.Linq.Mapping.TableAttribute), true);
//Get table name
String table = (info[0] as System.Data.Linq.Mapping.TableAttribute).Name;
//Full text search on that table
return context.ExecuteQuery<TSource>(String.Concat("SELECT * FROM ", table, " WHERE CONTAINS(*, {0})"), text);
}
And added this wrapper to each partial Linq class where there is a full text index
public static IEnumerable<Pet> FullTextSearch(string text, MyDataContext context)
{
return (LinqUtilities.GenericFullTextSearch<Pet>(text, context) as IEnumerable<Pet>);
}
So now I can do full text searches with neat stuff like
var Pets = Pet.FullTextSearch(helloimatextbox.Text, MyDataContext).Skip(10).Take(10);
I'm assuming only a very basic search is necessary at present. Can anyone improve on this? Is it possible to implement as an extension method and avoid the wrapper?
The neatest solution is to use an inline table valued function in sql and add it to your model
http://sqlblogcasts.com/blogs/simons/archive/2008/12/18/LINQ-to-SQL---Enabling-Fulltext-searching.aspx
To get it working you need to create a table valued function that does
nothing more than a CONTAINSTABLE query based on the keywords you
pass in,
create function udf_sessionSearch
(#keywords nvarchar(4000)) returns table as return (select [SessionId],[rank]
from containstable(Session,(description,title),#keywords))
You then add this function to your LINQ 2 SQL model and he presto you
can now write queries like.
var sessList = from s in DB.Sessions
join fts in DB.udf_sessionSearch(SearchText) on s.sessionId equals fts.SessionId
select s;
I was pretty frustrated with the lack of clear examples... especially when there are potentially large data sets and paging is needed. So, here's an example that hopefully encompasses everything you might need :-)
create function TS_projectResourceSearch
( #KeyStr nvarchar(4000),
#OwnId int,
#SkipN int,
#TakeN int )
returns #srch_rslt table (ProjectResourceId bigint not null, Ranking int not null )
as
begin
declare #TakeLast int
set #TakeLast = #SkipN + #TakeN
set #SkipN = #SkipN + 1
insert into #srch_rslt
select pr.ProjectResourceId, Ranking
from
(
select t.[KEY] as ProjectResourceId, t.[RANK] as Ranking, ROW_NUMBER() over (order by t.[Rank] desc) row_num
from containstable( ProjectResource,(ResourceInfo, ResourceName), #KeyStr )
as t
) as r
join ProjectResource pr on r.ProjectResourceId = pr.ProjectResourceId
where (pr.CreatorPersonId = #OwnId
or pr.ResourceAvailType < 40)
and r.row_num between #SkipN and #TakeLast
order by r.Ranking desc
return
end
go
select * from ts_projectResourceSearch(' "test*" ',1002, 0,1)
Enjoy,
Patrick
I use a little hack using Provider Wrapper techniques. I have a c# code that rewrite magic word in SQL with FTS search for MS SQL (you can adjust for any server you like).
if you have context class MyEntities, create subclass like
public class MyEntitiesWithWrappers : MyEntities
{
private IEFTraceListener listener;
public string FullTextPrefix = "-FTSPREFIX-";
public MyEntitiesWithWrappers(): this("name=MyEntities")
{
}
public MyEntitiesWithWrappers(string connectionString)
: base(EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(connectionString,"EFTracingProvider"))
{
TracingConnection.CommandExecuting += RewriteFullTextQuery;
}
/// <summary>
/// Rewrites query that contains predefined prefix like: where n.NOTETEXT.Contains(Db.FullTextPrefix + text) with SQL server FTS
/// To be removed when EF will support FTS
/// </summary>
/// <param name="o"></param>
/// <param name="args"></param>
public void RewriteFullTextQuery(object o, CommandExecutionEventArgs args)
{
var text = args.Command.CommandText;
for (int i = 0; i < args.Command.Parameters.Count; i++)
{
DbParameter parameter = args.Command.Parameters[i];
if (parameter.DbType.In(DbType.String, DbType.AnsiString, DbType.StringFixedLength, DbType.AnsiStringFixedLength))
{
if (parameter.Value == DBNull.Value)
continue;
var value = (string) parameter.Value;
parameter.Size = 4096;
if (value.IndexOf(FullTextPrefix) >= 0)
{
value = value.Replace(FullTextPrefix, ""); // remove prefix we added n linq query
value = value.Substring(1, value.Length-2); // remove %% escaping by linq translator from string.Contains to sql LIKE
parameter.Value = value;
args.Command.CommandText = Regex.Replace(text,
string.Format(#"\(\[(\w*)\].\[(\w*)\]\s*LIKE\s*#{0}\s?(?:ESCAPE '~')\)", parameter.ParameterName),
string.Format(#"contains([$1].[$2], #{0})", parameter.ParameterName));
}
}
}
}
}
And then use it like this:
var fullTextSearch = Db.FullTextPrefix + textToSearch;
var q = Db.Notes.Where(n => !n.Private && n.NoteText.Contains(fullTextSearch));
A slighty nicer method (takes rank into effect) using CONTAINSTABLE
String pkey = context.Mapping.GetTable(typeof(TSource)).RowType.DataMembers.SingleOrDefault(x => x.IsPrimaryKey).Name;
string query = String.Concat(#"SELECT *
FROM ", table, #" AS FT_TBL INNER JOIN
CONTAINSTABLE(", table, #", *, {0}) AS KEY_TBL
ON FT_TBL.", pkey, #" = KEY_TBL.[KEY]
ORDER BY KEY_TBL.[RANK] DESC");
return context.ExecuteQuery<TSource>(query, text);
.NET Core 2.1 and above supports an extension method that allows the use of FREETEXT and FREETEXTTABLE searches
using Microsoft.EntityFrameworkCore;
var results = dbContext.MyTable
.Where(e => EF.Functions.FreeText("*", "search criteria"));
The FreeText function is defined in Microsoft.EntityFrameworkCore.SqlServer so your project must reference that package.
Documentation
I've been trying to solve the exact problem. I like to write my SQL logic in my LINQtoSQL but I needed a way to do Full Text Search. right now I'm just using SQL functions and then calling the user-defined functions inline of the linq queries. not sure if that's the most efficient way. what do you guys think?
You can just do something like this
var results = (from tags in _dataContext.View_GetDeterminationTags
where tags.TagName.Contains(TagName) ||
SqlMethods.Like(tags.TagName,TagName)
select new DeterminationTags
{
Row = tags.Row,
Record = tags.Record,
TagID = tags.TagID,
TagName = tags.TagName,
DateTagged = tags.DateTagged,
DeterminationID = tags.DeterminationID,
DeterminationMemberID = tags.DeterminationMemberID,
MemberID = tags.MemberID,
TotalTagged = tags.TotalTagged.Value
}).ToList();
Notice where TagName.Contains also the SQLMethods.Like just do a using
using System.Data.Linq.SqlClient;
to gain access to that SQLMethods.
dswatik - the reason for wanting full text search is that .contains translates to
SELECT * FROM MYTABLE WHERE COLUMNNAME LIKE '%TEXT%'
Which ignores any indexes and is horrible on a large table.

Resources