Linq-Sql IQueryable<T> and chaining OR operations - linq-to-sql

I'm trying to simulate:
WHERE x.IsActive = true OR x.Id = 5
The following causes 'AND' to be used... how do I simulate an 'OR' condition with IQueryable (qry) and my nullable int, given that other filtering might be involved as with the IsActive filter here?
if (onlyActiveItems) //bool
{
qry = qry.Where(x => x.IsActive == true);
}
if (whenSpecifiedMustIncludeRecordWithThisId.HasValue) //int?
{
qry = qry.Where(x => x.Id == whenSpecifiedMustIncludeRecordWithThisId.Value);
}
I have considered union but its seems the answer to this should be much simpler.
This is one solution which gets around the problem I get with "Nullable object must have a value" when trying the combined all in one answer. What causes the nullable to be evaluated when it is null otherwise?
if (whenSpecifiedMustIncludeRecordWithThisId.HasValue)
{
qry = qry.Where(x => (!onlyActiveItems || (onlyActiveItems && x.IsActive)) || x.Id == whenSpecifiedMustIncludeRecordWithThisId.Value);
}
else
{
qry = qry.Where(x => (!onlyActiveItems || (onlyActiveItems && x.IsActive)));
}
It seems also in some cases the use of the nullable's .Value property makes a difference as seen in another question of mine here Linq to SQL Int16 Gets Converted as Int32 In SQL Command

Try this:
qry = qry.Where(x => (onlyActiveItems
? x.IsActive
: false) ||
(whenSpecifiedMustIncludeRecordWithThisId.HasValue
? x.Id == whenSpecifiedMustIncludeRecordWithThisId
: false) ||
(!onlyActiveItems && !whenSpecifiedMustIncludeRecordWithThisId.HasValue));
Note that we're comparing an int? to an int, not two ints.
I am assuming here that the point of the query is to filter out if certain conditions are met.
If onlyActiveItems is true, it verifies whether the IsActive field is true
If whenSpecifiedMustIncludeRecordWithThisId.HasValue is true it verifies whether the value matches the Id field
If both are true it will logically OR the conditions
If both are false all records are displayed (if this is not the intent, you can remove the last condition)

When working with "int?" I usually compare them using object.Equals(i1, i2), for example
from r in cxt.table
where object.Equals(r.column, nullableInt)
select r
This avoids all nullable issues.

Related

How to pass in operators to SQL from NodeJS

In my NodeJS app, I want the user to be able to pass in a filter into a mySQL (v8.0.20) query (using Knex):
const sql = 'SELECT * FROM xyz WHERE id = ? AND ?? ? ?';
The series of question marks at the end is where I want to add in the filter, e.g. id > 3. I know one question mark indicates a value and two indicates an attribute/table name. But neither work for <,>,=. How do I tell SQL that this is a built-in operator?
You can't use parameters to supply structural parts of an SQL query. Parameters are meant to be value placeholders.
If you scrutinize the user-supplied field names and operators properly, you can build the SQL query dynamically. Keep the ? for user-supplied values.
const allowedOperators = ['=', '>', '>=', '<', '<=', '!='];
const allowedFields = ['id', 'name', 'etc'];
if (
allowedOperators.indexOf(userSuppliedOperator) > -1 &&
allowedFields.indexOf(userSuppliedField.toLowerCase()) > -1
) {
var sql = `SELECT * FROM xyz WHERE id = ? AND {userSuppliedField} {userSuppliedOperator} ?`;
// use SQL string
} else {
throw new Error("Invalid search parameters");
}

Laravel 5.8 BIT(1) datatype issue

I have a column enabled with datatype bit(1). I am trying to save 0 or 1 value in Database by Laravel eloquent.
$model->enabled = $inputs['enabled'];
$model->save();
I have saved values in my config file.
'enabled' => [
'0' => 'No',
'1' => 'Yes',
],
But when I tried to save these value in database. I was getting error like,
SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'enabled' at row 1
when i ran query in mysql phpmyadmin, it saved data correctly database.
But running this query by eloquent, it produces error.
you need tinyint type, in your migration file do
$table->boolean('enabled')->default(false);
When you migrate with boolean('column_name') it creates a column with type tinyint(1) and you can set to model true/1 or false/0 and save. For example
$model->boolean_field = true;
$model->save();
Or
$model->boolean_field = 1;
$model->save();
As per MySQL manual you can use should use bool and boolean which are aliases of tinyint to store 0 or 1 value
TINYINT: A value of
zero is considered false. Non-zero
values are considered true.
So use:
$table->tinyInteger('enabled');
https://dev.mysql.com/doc/refman/8.0/en/other-vendor-data-types.html
A boolean in mysql is generaly a tinyint.
Eloquent models can cast boolean automaticaly : https://laravel.com/docs/6.x/eloquent-mutators#attribute-casting
protected $casts = [
'enabled' => 'boolean',
];
Before saving your model, make sure your variable is a boolean
$model->enabled = $inputs['enabled']==='Yes';
$model->save();
also you can use mutator to force values.
example : in your model, append :
public function setEnabled($value) // note the E in uppercase.
{
if ($value=='YES') { $this->attributes['enabled'] = 1;
if ($value=='NO') { $this->attributes['enabled'] = 0;
if ($value=='1') { $this->attributes['enabled'] = 1;
if ($value=='0') { $this->attributes['enabled'] = 0;
// etc...
// the logic can be improved... yes/YES/No/no/0/1/empty/null/ etc..
}
and in the client code
$model->enabled = 'YES'; // || 'NO' || etc.., : note the e in lowercase.
then method setEnabled is called during assignation and 'enabled' will become 1
doc : https://laravel.com/docs/5.8/eloquent-mutators
So i had solved my question by just adding DB::raw();
like,
$model->enabled = DB::raw($inputs['enabled']);
$model->save();
Eloquent doesn't work by calling Boolean value directly, first you have to gone through your values in DB::raw();
It works like a charm.

Codeigniter mysql where not equal to query

Mysql codeigniter query is not working properly.
Suppose if mysql table looks like this:
user_id|user_name
1|john
2|alex
3|sam
Here user_name is unique
The following query should return false if user_name=john and user_id=1 and true if say user_name=john and user_id=2.
$this->db->get_where('user', array('user_name' => $name,'user_id !=' => $userid));
But it returns true in the case user_name=john and user_id=1.
Can anyone suggest me an alternative way of querying not equal to.
print($this->db->last_query()) gives:
SELECT * FROM (user) WHERE user_name = 'john' AND user_id != '1'
Why dont you use simple $this->db->query('your query');
Simply try this, Add the desired condition in the where function.
$this -> db -> where('invitee_phone !=', $user_phone);
You can go follwoing way too. It work for me
$total = 5;
$CI = get_instance();
$CI->load->database();
$CI->db->order_by('id','asc');
$topusers = $CI->db->get_where('users',array('user_type != 1 && `status` =' => 1),$total,0);
echo $CI ->db ->last_query();
die;
and if still not work for you can go with #rohit suggest: $this->db->query('your query');
Type 1:
Using ->where("column_name !=",$columnname) is fine for one column.
But if you want to check multi columns, you have to form an array inside where clause.
Like this
$whereArray = array(
"employee_name" => $name,
"employee_id !=" => $id,
);
$this->db->select('*')->from('employee')->where($whereArray);
Type 2:
We can just write exactly what we want inside where.
Like
$thi->db->where(("employee_id =1 AND employee name != 'Gopi') OR designation_name='leader#gopis clan'");
Type 2 is good for working with combining queries, i mean paranthesis "()"
you can follow this code:
$query = $this->db->select('*')->from('employee')->where('user_name', $name)->where('user_id !=', $userid)->get();
$last_query = $this->db->last_query();
$result = $query->result_array();
if you pass $name = 'john' and $userid = '1' then it return empty array.
The problem with using $this->db->query('your query'); is that it is not portable. One of the most important reasons to embrace the query builder methods is so that no matter what database driver you use, CodeIgniter ensures that the syntax is appropriate.
If a bit of discussion was possible, I'd probably like to hear why you need composite primary identifiers in your table and I'd like to see what your table schema looks like. However, I think the time for discussion has long passed.
Effectively, you want to return a boolean result stating the availability of the combination of the username AND the id -- if one is matched, but not both, then true (available).
To achieve this, you will want to search the table for an exact matching row with both qualifying conditions, count the rows, convert that integer to a boolean, then return the opposite value (the syntax is simpler than the explanation).
Consider this clean, direct, and portable one-liner.
return !$this->db->where(['user_name' => $name,'user_id' => $userid])->count_all_results('user');
this will return false if the count is > 0 and true if the count is 0.

CurrentUtcDateTime does not exist - Entity Framework and MySql

I am having a problem with canonical functions in Entity Framework 4.1 and MySql Connector/Net 6.4.3.
According to Microsoft cannonical functions are understood and translated into the local SQL dialect by all database providers from the SQL generated by LINQ; http://msdn.microsoft.com/en-us/library/bb738626.aspx However, my code chokes on CurrentUtcDateTime(), which is listed here; http://msdn.microsoft.com/en-us/library/bb738563.aspx
Here is the LINQ query (from NopCommerce) that generates the offensive SQL:
public List<Poll> GetPolls(int languageId, int pollCount, bool loadShownOnHomePageOnly)
{
bool showHidden = NopContext.Current.IsAdmin;
var query = (IQueryable<Poll>)_context.Polls;
if (!showHidden)
{
query = query.Where(p => p.Published);
query = query.Where(p => !p.StartDate.HasValue || p.StartDate <= DateTime.UtcNow);
query = query.Where(p => !p.EndDate.HasValue || p.EndDate >= DateTime.UtcNow);
}
if (loadShownOnHomePageOnly)
{
query = query.Where(p => p.ShowOnHomePage);
}
if (languageId > 0)
{
query = query.Where(p => p.LanguageId == languageId);
}
query = query.OrderBy(p => p.DisplayOrder);
if (pollCount > 0)
{
query = query.Take(pollCount);
}
var polls = query.ToList();
return polls;
}
query.ToList() generates the SQL below:
SELECT`Project1`.`PollID`, `Project1`.`LanguageID`, `Project1`.`Name`,
`Project1`.`Published`, `Project1`.`ShowOnHomePage`, `Project1`.`DisplayOrder`,
`Project1`.`SystemKeyword`, `Project1`.`StartDate`, `Project1`.`EndDate`
FROM (SELECT`Extent1`.`PollID`, `Extent1`.`LanguageID`, `Extent1`.`Name`,
`Extent1`.`SystemKeyword`, `Extent1`.`Published`, `Extent1`.`ShowOnHomePage`,
`Extent1`.`DisplayOrder`, `Extent1`.`StartDate`, `Extent1`.`EndDate`
FROM `Nop_Poll` AS `Extent1` WHERE ((((`Extent1`.`Published` = 1) AND
((`Extent1`.`StartDate` IS NULL) OR (`Extent1`.`StartDate` <= (CurrentUtcDateTime()))))
AND ((`Extent1`.`EndDate` IS NULL) OR (`Extent1`.`EndDate` >= (CurrentUtcDateTime()))))
AND (`Extent1`.`ShowOnHomePage` = 1)) AND (`Extent1`.`LanguageID` = #p__linq__0))
AS `Project1` ORDER BY `Project1`.`DisplayOrder` ASC LIMIT 2147483647
This is error is outputed:
*FUNCTION myDatabase.CurrentUtcDateTime does not exist
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: MySql.Data.MySqlClient.MySqlException: FUNCTION myDatabase.CurrentUtcDateTime does not exist*
Am I missing something? Please advice. Thanks.
I encountered this exact same problem and lost almost two days trying to figure it out. It appears to be a bug in the EntityFramework mappings for MySql.
The solution is to move the DateTime.UtcNow calculation outside of the scoped lambda and plug in the actual value.
var utcNow = DateTime.UtcNow;
query = query.Where(p => p.Published);
query = query.Where(p => !p.StartDate.HasValue || p.StartDate <= utcNow);
query = query.Where(p => !p.EndDate.HasValue || p.EndDate >= utcNow);
Based on Bohemian's suggestion, I fixed this issue with a "bypass" function.
CREATE FUNCTION `your_schema`.`CurrentUtcDateTime` ()
RETURNS TIMESTAMP DETERMINISTIC
RETURN UTC_TIMESTAMP();
Use UTC_TIMESTAMP()

Help building up LINQ query when using anonymous types

I've started out with:
IQueryable<Author> authors2 = db.Authors;
Then I build up authors2 in multiple if statements, here's one of them
authors2 = authors2.Where(t => t.ItemAuthors.Any(b => b.Item.CategoryItems.Any(z => z.categoryID == int.Parse(ddlCategory.SelectedValue))));
Then finally I would like to append this to the end of the built up where clauses
authors2.OrderBy(x => x.text).Select(x => new
{
authorText = string.Format("{0} ({1})",x.text, x.ItemAuthors.Count())
});
To bind a control like this:
ddlAuthor.DataSource = authors2;
ddlAuthor.DataTextField = "authorText";
ddlAuthor.DataBind();
Apparently the compiler is not very happy about my select new statement. How can I rewrite this to achieve the same goal? I believe this is called creating an anonymous type.
It says an explicit conversion exists(are you missing a cast?) I can't figure out how to cast it.
In your third statement, the returned type is not same as authors2 because the Select projects a different type other than Author
So assign the value to a new variable
var authorsFinal = authors2
.OrderBy(x => x.text)
.Select(x => new
{
authorText = string.Format("{0} ({1})",
x.text,
x.ItemAuthors.Count())
});