How to write a dynamic where 'like' query in Entity framework? - entity-framework

Here is my code:
//order my baselist is context.Entity
public static GridData Getdata<T>(ObjectSet<T> baseList,
int currentPage,
int rowsPerPage,
string sortcolumn,
string sortord,
string searchQuery,
string searchColumns)where T: class{
var query = baseList.OrderBy("it." + sortcolumn + " " + sortord);
string strPredicate = string.Empty;
if (!string.IsNullOrEmpty(searchColumns))
{
strPredicate = "it." + searchColumns + " LIKE #" + searchColumns + " ";
query = baseList.Where(strPredicate, new ObjectParameter(searchColumns, searchQuery)).OrderBy("it." + sortcolumn + " " + sortord);
}
}
My problem is i am trying to write down or form a like query in entity framework and seems like it does not support it.

You can use .Contains which is the LIKE operator equivalent in entity framework.

you can use this
query = baseList.Where(baseli=>baseli.Contains(searchColumns )).OrderBy("it." + sortcolumn + " " + sortord);
:)

Related

How to make native query for nested projection in Spring Data JPA

I need to write a native query for my projection with nested interfaces.
My TransactionView interface:
public interface TransactionView {
Long getId();
TransactionType getType();
LocalDate getDate();
AccountProjection getAcc1();
AccountProjection getAcc2();
interface AccountProjection {
String getName();
CurrencyName getCurrencyCode();
BigDecimal getBalance();
}
BigDecimal getAmount();
PartnerView getPartner();
interface PartnerView {
String getName();
}
String getComment();
CategoryView getCategory();
interface CategoryView {
String getName();
}
}
JpaRepository:
public interface TransactionsRepository extends JpaRepository<Transaction, Long> {
List<TransactionView> findByAcc1PersonIdOrderByDateDesc(int personId);
}
This approach works good and I get JSON like this:
[{
"id":34,
"type":"TRANSFER",
"comment":"test comment",
"date":"2022-12-23",
"amount":200.00,
"acc2":
{
"name":"cash",
"currencyCode":"USD",
"balance":200.00
},
"acc1":
{
"name":"test acc",
"currencyCode":"USD",
"balance":700.00
},
"partner":null,
"category":null
},
{
"id":20,
"type":"EXPENCE",
"comment":"",
"date":"2022-12-13",
"amount":33.07,
"acc2":null,
"acc1":
{
"name":"cash",
"currencyCode":"BYN",
"balance":322.33
},
"partner":
{
"name":"bmw"
},
"category":
{
"name":"auto"
}
}]
But Hibernate generates a very complex query with a lot of extra columns fetching.
My native query returns null nested objects:
#Query(value = "SELECT t.id AS id, " +
"t.transaction_type AS type, " +
"t.transaction_date AS date, " +
"t.amount AS amount, " +
"t.comment AS comment, " +
"a1.balance AS acc1Balance, " +
"a1.currency_code AS acc1CurrencyCode, " +
"a1.name AS acc1Name, " +
"a2.balance AS acc2Balance, " +
"a2.currency_code AS acc2CurrencyCode, " +
"a2.name AS acc2Name, " +
"par.name AS partnerName, " +
"cat.name AS categoryName, " +
"cat.category_type AS categoryType " +
"FROM transaction t " +
"LEFT OUTER JOIN account a1 ON t.acc1_id=a1.id " +
"LEFT OUTER JOIN person per ON a1.person_id=per.id " +
"LEFT OUTER JOIN account a2 ON t.acc2_id=a2.id " +
"LEFT OUTER JOIN partner par ON t.partner_id=par.id " +
"LEFT OUTER JOIN category cat ON t.category_id=cat.id " +
"WHERE per.id=?1 ORDER BY t.transaction_date DESC", nativeQuery = true)
List<TransactionView> findByAcc1PersonIdOrderByDateDescTest(int personId);
[{
"id":34,
"type":"TRANSFER",
"comment":"test comment",
"date":"2022-12-23",
"amount":200.00,
"acc2":null,
"acc1":null,
"partner":null,
"category":null
},
{
"id":20,
"type":"EXPENCE",
"comment":"",
"date":"2022-12-13",
"amount":33.07,
"acc2":null,
"acc1":null,
"partner":null,
"category":null
}]
Also I tried approach from Peter Gyschuk, but it doesn't work.
How can I solve it using native query?

Creating new Objects in JPQL returns only one object

I have a JPA Entity with a large number of fields and millions of records. For a report, I need only some of the fields. So I want to create an Object with the essential fields due to resource constraints. I tried to create a list of new objects in JPQL. It gives only one object as a result, where multiple objects are expected.
String j;
j = "select new lk.gov.health.phsp.pojcs.ClientEncounterComponentBasicDataToQuery("
+ "f.name, "
+ "f.code, "
+ "f.item.code, "
+ "f.shortTextValue, "
+ "f.integerNumberValue, "
+ "f.longNumberValue, "
+ "f.realNumberValue, "
+ "f.booleanValue, "
+ "f.dateValue, "
+ "f.itemValue.code"
+ ") ";
j += " from ClientEncounterComponentItem f "
+ " where f.retired=false "
+ " and f.encounter.id=:eid";
Map m = new HashMap();
m.put("eid", endId);
The EBJ is as follows.
public List<Object> findObjects(String jpql, Map<String, Object> parameters, TemporalType tt) {
TypedQuery<Object> qry = getEntityManager().createQuery(jpql, Object.class);
Set s = parameters.entrySet();
Iterator it = s.iterator();
while (it.hasNext()) {
Map.Entry m = (Map.Entry) it.next();
Object pVal = m.getValue();
String pPara = (String) m.getKey();
if (pVal instanceof Date) {
Date pDate = (Date) pVal;
qry.setParameter(pPara, pDate, TemporalType.DATE);
} else {
qry.setParameter(pPara, pVal);
}
}
try {
return qry.getResultList();
} catch (Exception e) {
return null;
}
}
What am I doing wrong? I am using EclipseLink as the persistence provider.

How to make a union query search using Criteria API

I tried to make a search in db for several fields using input string.
What i've got using HQL.
#Override
public List<Teacher> searchByString(String str) {
String[] fields = {"fam", "name", "otch", "phoneNumber"};
List<Teacher> result = new ArrayList<>();
for (int i = 0; i < fields.length-1 ; i++) {
result.addAll(em.createQuery(
"SELECT c FROM Teacher c WHERE lower(c." + fields[i] + ") LIKE lower(?1)")
.setParameter("1", "%" + str + "%")
.getResultList());
}
result.addAll(em.createQuery(
"SELECT c FROM Teacher c WHERE to_char(c." + "dateOfBirth, 'yyyy-mm-dd'" + ") LIKE ?1")
.setParameter("1", "%" + str + "%")
.getResultList());
return result;
}
This example working, but i need to have it in Criteria. I found nothing about "union" in Criteria API. How can i achive this result?

azure REST API communication

I'm currently trying retrieve list share available in my Azure account from salesforce. I'm trying to implement the example from below sample code:
https://learn.microsoft.com/en-us/rest/api/storageservices/list-shares#samplerequestandresponse
//private key: access key of my account
string storageKey =private key;
string storageName = 'accountName';
Datetime dt = Datetime.now();
string formattedDate = dt.formatGMT('EEE, dd MMM yyyy HH:mm:ss')+ ' GMT';
system.debug('formattedDate--'+formattedDate);
string CanonicalizedHeaders = 'x-ms-date:'+formattedDate+'\nx-ms-version:2016-05-31';
string CanonicalizedResource = '/' + storageName + '/\ncomp:list';
string StringToSign = 'GET\n\n\n\n\n\n\n\n\n\n\n\n' + CanonicalizedHeaders+'\n'+CanonicalizedResource;
system.debug('StringToSign--'+StringToSign);
Blob temp = EncodingUtil.base64Decode(storageKey);
Blob hmac = Crypto.generateMac('HmacSHA256',Blob.valueOf(StringToSign),temp ); //StringToSign
system.debug('oo-'+EncodingUtil.base64Encode(hmac));
HttpRequest req = new HttpRequest();
req.setMethod('GET');
//req.setHeader('content-type', 'application/xml');
req.setHeader('x-ms-version','2016-05-31' );
req.setHeader('x-ms-date', formattedDate);
string signature = EncodingUtil.base64Encode(hmac);
string authHeader = 'SharedKey salesforcestrongaccount'+':'+signature;
req.setHeader('Authorization',authHeader);
req.setEndpoint('https://<accountName>.file.core.windows.net/?comp=list');
Http http = new Http();
HTTPResponse res;
res = http.send(req);
System.debug(LoggingLevel.INFO, 'http.send result status: ' + res.getStatus());
Any help?
As Gaurav Mantri says, there are something wrong with your stringToSign. So you will get this error.
The right Shared Key Authentication is like this:
StringToSign = VERB + "\n" +
Content-Encoding + "\n" +
Content-Language + "\n" +
Content-Length + "\n" +
Content-MD5 + "\n" +
Content-Type + "\n" +
Date + "\n" +
If-Modified-Since + "\n" +
If-Match + "\n" +
If-None-Match + "\n" +
If-Unmodified-Since + "\n" +
Range + "\n" +
CanonicalizedHeaders +
CanonicalizedResource;
Here I create a test demo, you could refer to it.
List share:
string storageAccount = "storage account";
string accessKey = "accountkey";
string resourcePath = "?comp=list";
string uri = #"https://" + storageAccount + ".file.core.windows.net/" + resourcePath;
// Web request
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = "GET";
request.Headers["x-ms-date"] = DateTime.UtcNow.ToString("R", System.Globalization.CultureInfo.InvariantCulture);
request.Headers["x-ms-version"] = "2015-02-21";
String stringToSign = "GET\n"
+ "\n" // content encoding
+ "\n" // content language
+ "\n" // content length
+ "\n" // content md5
+ "\n" // content type
+ "\n" // date
+ "\n" // if modified since
+ "\n" // if match
+ "\n" // if none match
+ "\n" // if unmodified since
+ "\n" // range
+ "x-ms-date:" + request.Headers["x-ms-date"] + "\nx-ms-version:2015-02-21\n" // headers
+ "/" + storageAccount + "/" + "\ncomp:list"; // resources
System.Security.Cryptography.HMACSHA256 hasher = new System.Security.Cryptography.HMACSHA256(Convert.FromBase64String(accessKey));
string strAuthorization = "SharedKey " + storageAccount + ":" + System.Convert.ToBase64String(hasher.ComputeHash(System.Text.Encoding.UTF8.GetBytes(stringToSign)));
request.Headers["Authorization"] = strAuthorization;
Task<WebResponse> response = request.GetResponseAsync();
HttpWebResponse responseresult = (HttpWebResponse)response.Result;
using (System.IO.StreamReader r = new System.IO.StreamReader(responseresult.GetResponseStream()))
{
string jsonData = r.ReadToEnd();
Console.WriteLine(jsonData);
}
Result:
Java:
private static final String account = "accountname";
private static final String key = "Key";
public static void main(String args[]) throws Exception {
// String urlString = "http://" + account + ".file.core.windows.net/sampleshare/name.txt";
String urlString = "https://" + account + ".file.core.windows.net/?comp=list";
HttpURLConnection connection = (HttpURLConnection) (new URL(urlString)).openConnection();
getFileRequest(connection, account, key);
connection.connect();
System.out.println("Response message : " + connection.getResponseMessage());
System.out.println("Response code : " + connection.getResponseCode());
BufferedReader br = null;
if (connection.getResponseCode() != 200) {
br = new BufferedReader(new InputStreamReader((connection.getErrorStream())));
} else {
br = new BufferedReader(new InputStreamReader((connection.getInputStream())));
}
System.out.println("Response body : " + br.readLine());
}
public static void getFileRequest(HttpURLConnection request, String account, String key) throws Exception {
SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
String date = fmt.format(Calendar.getInstance().getTime()) + " GMT";
String stringToSign = "GET\n" + "\n" // content encoding
+ "\n" // content language
+ "\n" // content length
+ "\n" // content md5
+ "\n" // content type
+ "\n" // date
+ "\n" // if modified since
+ "\n" // if match
+ "\n" // if none match
+ "\n" // if unmodified since
+ "\n" // range
+ "x-ms-date:" + date + "\nx-ms-version:2015-02-21\n" // headers
+ "/" + account + request.getURL().getPath() + "\ncomp:list"; // resources
System.out.println("stringToSign : " + stringToSign);
String auth = getAuthenticationString(stringToSign);
request.setRequestMethod("GET");
request.setRequestProperty("x-ms-date", date);
request.setRequestProperty("x-ms-version", "2015-02-21");
request.setRequestProperty("Authorization", auth);
}
private static String getAuthenticationString(String stringToSign) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(Base64.decode(key), "HmacSHA256"));
String authKey = new String(Base64.encode(mac.doFinal(stringToSign.getBytes("UTF-8"))));
String auth = "SharedKey " + account + ":" + authKey;
return auth;
}

Entity SQL Datetime Syntax error

Anyone know What is wrong with my syntax here? I am making dynamic eSQL Queries and running into an error when trying to make where condition for DateTime data type. This is the error:
The query syntax is not valid. Near term '2011', line 1, column 135.
If it matters the DateTime type in my entity is actually nullable DateTime?
However, I thought this is the correct syntax from everything I've read.
Here is the code:
List<EntityFilter<FirstRead>> filters = new List<EntityFilter<FirstRead>>()
{
new EntityFilter<StudyFirstRead> { PropertyName = "username", OpType = ExpressionType.Equal, Value = "cwoodhouse" },
new EntityFilter<StudyFirstRead> { PropertyName = "FirstRead", OpType = ExpressionType.LessThan, Value = "DATETIME'2011-02-01 00:00'" }
};
Where EntityFilter is:
public class EntityFilter<T>
{
public string PropertyName { get; set; }
public ExpressionType OpType { get; set; }
public object Value { get; set; }
And I am building dynamic queries like so:
StringBuilder builder = new StringBuilder();
int counter = 0;
string baseStr = #"SELECT VALUE val FROM " + contextName + "." + tableName + " AS val WHERE val.";
builder.Append(baseStr);
foreach (EntityFilter<T> filter in filters)
{
//builder.Append(filter.PropertyName + " " + filter.OpTypeString() + " #p" + counter);
builder.Append(filter.PropertyName + " " + filter.OpTypeString() + "'" + filter.Value + "'");
counter++;
if (counter < filters.Count)
builder.Append(" AND val.");
else
{
break;
}
}
return builder.ToString();
It actually is the correct syntax for entity SQL (different than regular SQL or T-SQL).
Turns out the problem was too many single quotes, because I had them in both the EntityFilter object and the method that built the dynamic query.
according to you code the end of your SQL statement would produce something like
AND val.FirstRead = 'DATETIME'2011-02-01 00:00''
when executed you will get error
Error 102: Incorrect syntax near '2011'.
obviously that is not syntactically correct SQL, the quick fix whould be to have your filters collection as such:
List<EntityFilter<FirstRead>> filters = new List<EntityFilter<FirstRead>>() {
new EntityFilter<StudyFirstRead> {
PropertyName = "username",
OpType = ExpressionType.Equal,
Value = "cwoodhouse"
}, new EntityFilter<StudyFirstRead> {
PropertyName = "FirstRead",
OpType = ExpressionType.LessThan,
Value = "2011-02-01 00:00"
}
};