RavenDB Query not working - ravendb

I can't seem to get this to work.
Basically I have a site that got a list of excluded brands and categories. which are stored like brands/1 category/123
I'm trying to query my product document and return first 20 results that don't have any excluded categories/ brands.
using (var session = documentStore.OpenSession())
{
var site = session.Load<Site>(193);
List<string> excludedCategories = session.Load<Category>(site.ExcludedCategories).Select(a => string.Format("brands/{0}",a.Id)).ToList();
var excludedBrands = session.Load<Brand>(site.ExcludedBrands).Select(a => string.Format("categories/{0}",a.Id)).ToList();
List<Product> ps = session.Query<Product>()
.Where(prod => excludedBrands.Any(a => !prod.Brands.Contains(a))
&& excludedCategories.Any(a => !prod.Categories.Contains(a)))
.OrderBy(a=>a.ProductGroup)
.Take(20)
.ToList();
}
Anyone let me know if I'm on the right lines?
Currently getting the following error:
Lucene.Net.QueryParsers.ParseException: Could not parse: '(: AND) AND -(: AND)' ---> Lucene.Net.QueryParsers.ParseException: Cannot parse '(: AND) AND -(: AND)': Encountered " ")" ") "" at line 1, column 8.
Was expecting one of:
...
"+" ...
"-" ...
"(" ...
"" ...
...
...
...
...
"[" ...
"{" ...
...
...
"" ...
---> Lucene.Net.QueryParsers.ParseException: Encountered " ")" ") "" at line 1, column 8.
Was expecting one of:
...
"+" ...
"-" ...
"(" ...
"*" ...
...
...
...
...
"[" ...
"{" ...
...
...

You cannot do a Contains operation during a query, that require computation and doesn't use an index.
Use the query like so:
List<Product> ps = session.Query<Product>()
.Where(prod => !prod.Brands.In(excludedBrands) &&
!prod.Categories.In(excludedCategories))
.OrderBy(a=>a.ProductGroup)
.Take(20)
.ToList();
If you still have an issue, call ToString() on the query and see what it actually does.

Related

Entity Framework if statement inside select

I have a problem in generating an Entity Framework query and not okay with linq style one :.....
This is my attempt:
var query = db.table
.Where(x => x.colA == 1)
.GroupBy(x => new {x.min,x.max})
.Select(y => if(y.key.min==0 && y.key.max==0)
{ " unchanged " }
else
{ y.key.min.tostring()+" "+y.key.max.tostring() })
.ToList()
I want to get "unchanged" string, if both value ofmin and max are zero, otherwise concat them
Use the conditional operator
// ...
.Select(y=> y.key.min==0 && y.key.max==0
? " unchanged "
: y.key.min.tostring()+" "+y.key.max.tostring())
// ...
Apparently all elements in your table have properties min and max
After GroupBy(x=> new {x.min,x.max}) you'll have a sequence of groups, where each group has a key {min, max}, all elements in the group have this value for their min and max properties.
After the GroupBy, you take every group, and from every group you'll select exactly one string. You get rid of the element of the group.
The string that you select depends on the key of the group: if the key = {0, 0} you select the string "unchanged", else you select the string:
y.key.min.tostring()+" "+y.key.max.tostring()
The result is a list of strings, something like:
"3 7",
"4 10,
"unchanged",
"2 8",
Are you sure you want this?
In that case you won't need the GroupBy. Distinct will be simpler and faster
List<string> result = db.table
.Where(tableRow => tableRow.colA == 1)
.Select(tableRow => tableRow.min==0 && tableRow.max==0
? " unchanged "
: tableRow.min.tostring()+" "+tableRow.max.tostring())
// from here you have a sequence of strings
// get rid of duplicates:
.Distinct()
.ToList();
For this specific case, you can use Conditional Operator (?:)
var query = db.table
.Where(x=> x.colA == 1)
.GroupBy(x=> new {x.min,x.max})
.Select(y=> (y.Key.min == 0 && y.Key.max == 0) ? " unchanged" : (y.Key.min.ToString()+" "+y.Key.max.ToString()))
.ToList();
Sorry I can't try it right now, but i think this should work
var query = db.table
.Where(x=> x.colA == 1)
.GroupBy(x=> new {x.min,x.max})
.Select(y=> {if(y.key.min==0 && y.key.max==0)
{
" unchanged "
} else
{
y.key.min.tostring()+" "+y.key.max.tostring();
} return y;})
.ToList()

Extra, blank row from PDO select on Sqlite

This involves a Sqlite database, PHP 7 and PDO. The query code is:
...
$stmt = $pdo->query('SELECT * FROM images');
while($row = $stmt->fetch(\PDO::FETCH_ASSOC)){
$images[] = [
"image_id" => $row["image_id"],
"date" => $row["date"],
"photographer" => $row["photographer"],
...
];
}
echo $stmt->rowCount() . " rows<br>";
echo count($images) . " images<br>";
var_dump($images);
return $images;
}
(Note: This is based on http://www.sqlitetutorial.net/sqlite-php/query/ . It will be revised soon to do prepared statements, enumerating cols, etc., once the problem described here is solved.)
The echos report "0 rows" and "2 images". The var_dump() outputs:
array(2) { [0]=> array(0) { } [1]=> array(14) { ["image_id"]=> ...
So clearly there's an extra, empty array in the first position in the outer array. In the calling code, which collects the $image array as return value, count($array) gives 2 not 1 (and code expecting name/value pairs in each row breaks).
The problem is, there's only one row in the table. This appears clearly on the command line: sqlite> select * from images; gets one row and:
sqlite> select count(*) as c from images;
1
What's wrong here?
Different array syntax solved it.
$stmt = $pdo->query('SELECT * FROM images');
$images = array();
while($row = $stmt->fetch(\PDO::FETCH_ASSOC)){
$images[] = array(
"image_id" => $row["image_id"],
"date" => $row["date"],
"photographer" => $row["photographer"],
...
);
}
I'm still not clear on the reason, but this way avoids the anomalous empty row.

Perl SQL::Parser table alias substitution: works for SELECT column names but not for WHERE column names

I'm trying to parse some SQL queries stored in a log database -- I don't want to submit them to a SQL database, just to extract the fields used in the SELECT and WHERE clause.
I've been fiddling with several SQL parsers in Java, Python and Perl. The one that seems to work better for my problem are SQL::Parser and SQL::Statement. With those I was able to write the following code:
#!/usr/bin/perl
use strict;
use SQL::Parser;
use SQL::Statement;
use Data::Dumper;
my $sql = "SELECT sl.plate,sp.fehadop FROM sppLines AS sl ".
"JOIN sppParams AS sp ON sl.specobjid = sp.specobjid ".
"WHERE fehadop < -3.5 ";
my $parser = SQL::Parser->new();
my $stmt = SQL::Statement->new($sql,$parser);
printf("COMMAND [%s]\n",$stmt->command);
printf("COLUMNS \n");
my #columns = #{$stmt->column_defs()};
foreach my $column ( #columns)
{
print " ".$column->{value}."\n";
}
printf("TABLES \n");
my #tables = $stmt->tables();
foreach my $table ( #tables)
{
print " ".$table->{name}."\n";
}
printf("WHERE COLUMNS\n");
my $where_hash = $stmt->where_hash();
print Dumper($where_hash);
Sorry if it is too long, it is the smallest, self-contained example I could devise.
The output of this code is:
COMMAND [SELECT]
COLUMNS
spplines.plate
sppparams.fehadop
TABLES
spplines
sppparams
WHERE COLUMNS
$VAR1 = {
'arg1' => {
'value' => 'fehadop',
'type' => 'column',
'fullorg' => 'fehadop'
},
'op' => '<',
'nots' => {},
'arg2' => {
'str' => '-?0?',
'fullorg' => '-3.5',
'name' => 'numeric_exp',
'value' => [
{
'fullorg' => '3.5',
'value' => '3.5',
'type' => 'number'
}
],
'type' => 'function'
},
'neg' => 0
};
The parser returns the name of columns (obtained through a call to $stmt->column_defs()) already renamed with the real tables names (e.g. spplines.plate instead of s1.plate) -- this is what I want.
I also want the names of the columns used in the WHERE clause.
I already know how to recursively parse the results of $stmt->where_hash() (didn't include the code to make the post clear), but even from dumping its contents I can see that the column names are not associated with the tables.
I would like to ensure that the columns names in the WHERE clause are also preceded by the tables name. After parsing the results of $stmt->where_hash() I would get sppparams.fehadop instead of fehadop.
Is this possible with SQL::Parser?
Thanks
(big edit -- tried to make the question clearer)
Since SQL::Statement has an eval_where, I suspect there might be a better way, but you can try a function like this:
get_column($stmt->column_defs(), $where_hash->{arg1});
sub get_column {
my ($columns, $arg) = #_;
return $arg->{fullorg} if ($arg->{type} ne 'column');
foreach my $col (#$columns) {
return $col->{value} if ($col->{fullorg} eq $arg->{fullorg});
my ($name) = ( $col->{fullorg} =~ /([^.]+)$/);
return $col->{value} if ($name eq $arg->{fullorg});
}
return $arg->{fullorg};
}

Sql ExecuteSqlCommand to LINQ

There's a way in LINQ to convert this following sql code ?
public Category SaveCategory(Category category, string tableName)
{
var context = new MyEntities();
context.Database.ExecuteSqlCommand("INSERT INTO " + tableName + " (title,description) VALUES {0}{1} ", table.title, table.description);
}
I want to avoid the use of conditions like "if" and "switch case" like :
case "Country": tableName= db.Countries.FirstOrDefault(x => x.id == id);
break;
case "City": tableName= db.Cities.FirstOrDefault(x => x.id == id);
break;
...
return tableName
If you can use Types instead of strings, you can use the Set method of the DbContext.
Type tableType = // type representing Country
DbSet mySet = db.Set(tableType);
mySet.Add(whatever);
Or you can access the Database property, but your code is potentially open to SQL injection. You should validate the string against a whitelist of valid table names, or do something else to remove the possibility of injection.
db.Database.ExecuteSqlCommand(...);

How to bind columns having special characters (space and comma) in a column name to a Kendo UI Grid?

I am getting error while bind a datatable to a Kendo Grid. My datatable column names may contains special characters such as spaces and comma.
View:
#(Html.Kendo().Grid(Model)
.Name("Test1Grid")
.Columns(columns =>
{
foreach (System.Data.DataColumn col in GridData.Columns)
{
columns.Bound(col.ColumnName).Title(col.Caption).ClientTemplate("#=kendo.toString(" + col.ColumnName + ", \"n0\")#");
}
}
)
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("GridData", "abc"))
.Model(model =>
{
foreach (System.Data.DataColumn column in GridData.Columns)
{
model.Field(column.ColumnName, column.DataType);
}
})
)
)
DataTable:
Name London New York Pittsburgh, PA Tokyo
order1 100 150 300 300
order2 500 650 800 350
The java script error i am getting here is "0x800a1391 - JavaScript runtime error: 'PA' is undefined"
Here is the detailed answer how i handled special charecters. once received the data from database, loop through columns and replace the columnname with valid identifier as:
string col_new;
foreach (DataColumn col in dt.Columns)
{
StringBuilder sb = new StringBuilder(col.ColumnName.ToString().Trim());
col_New = sb.Replace(" ", "SPACE").Replace(",", "COMMA").ToString();
}
dt.Columns[ColumnName].ColumnName = col_New;
return dt;
Then when bound the columns in Kendo grid in a headertemplate just replace back the the words "SPACE" and "COMMA" with the signs " " and "," respectively.
foreach (System.Data.DataColumn col in Model.Columns)
{
columns.Bound(col.ColumnName)
.Title(col.ColumnName)
.HeaderTemplate("col.ColumnName.ToString().Trim().Substring(3).Replace("SPACE", " ").Replace("AND", "&"))
}
It is not a bug. There cannot be special characters or spaces in field names.
It is stated clearly here in the Kendo documentation.
To summarize, and I quote: "The field name should be a valid Javascript identifier and should contain no spaces, no special characters, and the first character should be a letter."
One thing you could do is prefix the field name(s) in question with a valid identifier.
You can try wrapping your column name in brackets []
columns.Bound(string.Format("[\"{0}\"]",col.ColumnName).Title(col.Caption).ClientTemplate("#=kendo.toString(" + col.ColumnName + ", \"n0\")#");
facing similar kind of issue.
I am trying to bind the column with my model.
columns.Bound(p => p.reportname).Title("Report Name").ClientTemplate("#= reportname#").Encoded(false);
When my reportname is "Test & Test" (or any special character).It is passing only "Test" to my action method.
I have tried with encoded(false/true) it didn't work.
So is there is any way so that I can pass column value (with special character &,*,# etc) to my action method.
Thanks