Count SQL Query not returning expected value - c#

I'm trying to have a method return a count statement.
public int getSettingsCount(string UserId, string Setting)
{
int LastSetting;
//var user = new SqlDataLayer();
using (var db = new SQLite.SQLiteConnection(this.DBPath))
{
{
List<int> _setting = db.Query<int>("SELECT COUNT(*) FROM QTabSettings WHERE UserId = 1058 AND Setting = 'ServerDropdown' GROUP BY UserId;");
LastSetting = Convert.ToInt32(_setting.SingleOrDefault());
}
return LastSetting;
}
}
When I execute the query it returns the correct value (6). However I am getting the value (0) from my above query.
How can I get the method to return the count as an int?

You are using LIMIT 1 and still using List<int> that's strange and unnecessary. Also since it's count(*) there is no need of LIMIT 1 since the result would be a scalar data. Should change it to
int _setting = db.Query<int>("SELECT COUNT(*) FROM QTabSettings WHERE UserId = 1058 AND Setting = 'ServerDropdown';");
LastSetting = _setting;

If I understand your question properly I think this is what you want:
LastSetting = _setting.FirstOrDefault();
or:
LastSetting = _setting[0];

Related

C# entity framework fromsqlraw query with includes (in) instead of where clause

What is the correct syntax for varname to make this query work?
I can get it to work with a single variable like
string varname = "TOTAL_NORWAY"
However, if I want to have a few variables in there, I get an empty array returned:
string varname = "'TOTAL_NORWAY', 'TOTAL_SWEDEN'";
return await _Context.theDataModel.FromSqlRaw(#"
select data
from data_table
where Variable in ({0})
", varname).ToListAsync();
Remember that you can combine FromSqlRaw with Linq:
string varnames = new [] { "TOTAL_NORWAY", "TOTAL_SWEDEN" };
var query = _Context.theDataModel.FromSqlRaw(#"
select data
from data_table");
query = query.Where(x => varnames.Contains(x.Variable));
// Add more where clauses as needed
return await query.ToListAsync();
ErikEJ's post was very helpful. The solution is not so trivial for someone who doesn't dabble in EF Core regularly.
I also had an extra where clause to consider, and this was done like so for anyone else wondering.
var items = new int[] { 1, 2, 3 };
var parameters = new string[items.Length];
var sqlParameters = new List<SqlParameter>();
for (var i = 0; i < items.Length; i++)
{
parameters[i] = string.Format("#p{0}", i);
sqlParameters.Add(new SqlParameter(parameters[i], items[i]));
}
sqlParameters.Add(new SqlParameter("#userid", "userXYZ123"));
var rawCommand = string.Format("SELECT * from dbo.Shippers WHERE ShipperId IN ({0}) and userid = {1}", string.Join(", ", parameters), "#userid");
var shipperList = db.Set<ShipperSummary>()
.FromSqlRaw(rawCommand, sqlParameters.ToArray())
.ToList();

C# Calculate field inside LINQ Query

I need some help to calculate a property inside my Linq query.
I know I need to use "let" somewhere, but I can't figure it out!
So, first I have this method to get my list from Database:
public BindingList<Builders> GetListBuilders()
{
BindingList<Builders> builderList = new BindingList<Builders>();
var ctx = new IWMJEntities();
var query = (from l in ctx.tblBuilders
select new Builders
{
ID = l.BuilderID,
Projeto = l.NomeProjeto,
Status = l.Status,
DataPedido = l.DataPedido,
DataPendente = l.DataPendente,
DataEntregue = l.DataEntregue,
DataAnulado = l.DataAnulado
});
foreach (var list in query)
builderList.Add(list);
return builderList;
}
Then, I have a function to calculate the Days between Dates accordingly to Status:
public int GetDays()
{
int Dias = 0;
foreach (var record in GetListBuilders)
{
if (record.Status == "Recebido")
{
Dias = GetBusinessDays(record.DataPedido, DateTime.Now);
}
else if (record.Status == "Pendente")
{
Dias = GetBusinessDays(record.DataPedido, (DateTime)record.DataPendente);
}
else if (record.Status == "Entregue")
{
Dias = GetBusinessDays(record.DataPedido, (DateTime)record.DataEntregue);
}
else if (record.Status == "Anulado")
{
Dias = GetBusinessDays(record.DataPedido, (DateTime)record.DataAnulado);
}
}
return Dias;
}
I need to call the GetDays in a DataGridView to give the days for each record.
My big problem is, How do I get this? include it in Linq Query? Calling GetDays() (need to pass the ID from each record to GetDays() function)!?
Any help?
Thanks
I think it would be easier to create an extension method:
public static int GetBusinessDays(this Builders builder) // or type of ctx.tblBuilders if not the same
{
if (builder == null) return 0;
switch(builder.status)
{
case "Recebido": return GetBusinessDays(builder.DataPedido, DateTime.Now);
case "Pendente": return GetBusinessDays(builder.DataPedido, (DateTime)builder.DataPendente);
case "Entregue": return GetBusinessDays(builder.DataPedido, (DateTime)builder.DataEntregue);
case "Anulado": GetBusinessDays(builder.DataPedido, (DateTime)builder.DataAnulado);
default: return 0;
}
}
Then, call it like that:
public BindingList<Builders> GetListBuilders()
{
BindingList<Builders> builderList = new BindingList<Builders>();
var ctx = new IWMJEntities();
var query = (from l in ctx.tblBuilders
select new Builders
{
ID = l.BuilderID,
Projeto = l.NomeProjeto,
Status = l.Status,
DataPedido = l.DataPedido,
DataPendente = l.DataPendente,
DataEntregue = l.DataEntregue,
DataAnulado = l.DataAnulado,
Dias = l.GetBusinessDays()
});
foreach (var list in query)
builderList.Add(list);
return builderList;
}
To do better, to convert a object to a new one, you should create a mapper.
Why does it need to be a part of the query? You can't execute C# code on the database. If you want the calculation to be done at the DB you could create a view.
You're query is executed as soon as the IQueryable is enumerated at the foreach loop. Why not just perform the calculation on each item as they are enumerated and set the property when you are adding each item to the list?

LINQ Dynamic Query with group by and string variable

I want to create a dynamic query with LINQ-to-SQL and everything works except for one thing: group by. I looked at the other questions but haven't found a reason so far why it does not work.
I use using System.Linq.Dynamic; with the following query (that works):
int numberOfRankedItems = 3;
string minMaxChoice = "max";
string orderBy = "";
if (minMaxChoice == "max")
{
orderBy = "queryGroup.Sum(row => row.POSITIONVALUE) descending";
} else if (minMaxChoice == "min")
{
orderBy = "queryGroup.Sum(row => row.POSITIONVALUE) ascending";
}
string minMaxFeatureColumnName = "BRANDNAME";
string selectMinMaxFeature = "new { minMaxFeature = queryGroup.Key." + minMaxFeatureColumnName + ", sumPosition = queryGroup.Sum(row => row.POSITIONVALUE)}";
var query = (from tableRow in Context.xxx
where /* some filters */
group tableRow by tableRow.BRANDNAME into queryGroup
orderby orderBy
select selectMinMaxFeature).Take(numberOfRankedItems).ToList();
The use of variables for orderby and select works fine, but for group by not no matter what I try to replace with a variable. The query actually works if I e.g. use a variable instead of tableRow.BRANDNAME but the query returns the wrong result. The goal is to be able to set the column for the grouping dynamically.
Ideas?
Thanks
Edit: there seem to be multiple issues also with the other variables. So I generalize the question a bit: how can I generalize the following query in terms of
The column to group by
The column to order by + ASC or DESC
In the select statement the columnname of the first statement (BRANDNAME)
Here is the query:
var query = (from tableRow in ctx.xxx
where /* filter */
group tableRow by new { tableRow.BRANDNAME } into queryGroup
orderby queryGroup.Sum(row => row.POSITIONVALUE) descending
select new { minMaxFeature = queryGroup.Key.BRANDNAME, sumPosition = queryGroup.Sum(row => row.POSITIONVALUE) }).Take(numberOfRankedItems).ToList();
Would be great without expression trees ;)
I have now elaborated a solution to the question:
The solution uses as before using System.Linq.Dynamic; allows now to set certain variables. In the end it returns a dictionary.
// set variables
int numberOfRankedItems;
if (queryData.NumberOfRankedItems != null)
{
numberOfRankedItems = (int) queryData.NumberOfRankedItems;
} else
{
numberOfRankedItems = 0;
}
string minMaxChoice = queryData.MinMaxChoice;
string minMaxFeatureColumnName = queryData.MinMaxFeatureColumnName;
string orderByPrompt = "";
if (minMaxChoice == "max")
{
orderByPrompt = "it.Sum(POSITIONVALUE) descending";
} else if (minMaxChoice == "min")
{
orderByPrompt = "it.Sum(POSITIONVALUE) ascending";
}
string groupByPrompt = queryData.MinMaxFeatureColumnName;
// execute query
IQueryable query = (from tableRow in Context.xxx
where /* some filters */
select tableRow).
GroupBy(groupByPrompt, "it").
OrderBy(orderByPrompt).
Select("new (it.Key as minMaxFeature, it.Sum(POSITIONVALUE) as sumPosition)").
Take(numberOfRankedItems);
// create response dictionary
Dictionary<int?, Dictionary<string, int?>> response = new Dictionary<int?, Dictionary<string, int?>>();
int count = 1;
foreach (dynamic item in query)
{
string minMaxFeatureReturn = item.GetType().GetProperty("minMaxFeature").GetValue(item);
int? sumPositionReturn = item.GetType().GetProperty("sumPosition").GetValue(item);
response[count] = new Dictionary<string, int?>() { { minMaxFeatureReturn, sumPositionReturn } };
count++;
}
return response;

Dynamic Linq using SqlFunction Checksum

I have this function which calculate an checksumAggregate on a set of rows that should themselves be checksum-med. Unfortunately if the tables don't have a unique INT column so the checksumAggregate isn't enough. I have to use Checksum to be able to use other columns.
I am using System.Linq.Dynamic to allow the function to be generic.
Where the code below references x.ColumnName.ToString() is what I need to replace with something like "ColumnName" like I do for the OrderBy and Where clause. (I would pass the string in another parameter of the function)
Since it uses SQLFunctions I am now stuck at how to do this. It's a shame there is no "*" for this function.
I really hope this makes sense. Any pointers in the right direction will be appreciated.
public int calculateChecksum<T>(IQueryable<T> query, string SortColumn, DateTime? TimeStamp, Int64 Offset = 0)
{
if (TimeStamp == null) {TimeStamp = new DateTime(1800,1,1);}
string filterExp = SortColumn + " = #0";
query = query.Where<T>(filterExp, TimeStamp);
query = query.OrderBy<T>(SortColumn);
query = query.Take(varTakeCount);
int outChecksum = SqlFunctions.ChecksumAggregate(query.Select(x => SqlFunctions.Checksum( x.ColumnName.ToString() )));
return outChecksum;
}
EDIT:
With a few tweaks I am able to get the ChecksumAggregate to work on a single INT column. Close, but not ideal.
string filterType = typeof(T).FullName.Split('.').LastOrDefault();
var p = Expression.Parameter(typeof(T), filterType);
var e = System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] { p }, null, "tablename.columnname");
int outChecksum = SqlFunctions.ChecksumAggregate(query.Select((Expression<Func<T, int>>)e));
Also I tried fooling around with stuff like this:
var checksumMethod = typeof (SqlFunctions).GetMethod("Checksum", new[] {typeof (string), typeof (string)});
var checksumExpression = Expression.Call(checksumMethod,e1,e1);
var e2=Expression.Lambda<Func<Int32>>(checksumExpression);
int outChecksum = SqlFunctions.ChecksumAggregate(query.Select(Expression<Func<T, bool>>)e2));
But can't quite make it passed runtime. I get a Nullable'1 Int32 can't be cast into an Int32. Sounds like it should.
EDIT 2:
Although this doesn't answer my original question I found a hack around it.
public int calculateChecksum<T, TContext>(DbContext context, IQueryable<T> query, string sortColumn, DateTime? TimeStamp, int Offset = 1)
{
if (TimeStamp == null) {TimeStamp = new DateTime(1800,1,1);}
string filterExp = sortColumn + " = #0";
query = query.Where<T>(filterExp, TimeStamp);
query = query.OrderBy<T>(sortColumn);
query = query.Take(Offset);
string sql = query.ToString();
sql = string.Format("select checksum_agg(BC) from ( select binary_checksum(*) as BC from ({0}) b ) c",sql);
int result = context.Database.SqlQuery<int>(sql).FirstOrDefault();
return result;
}
I need a beer!

ServiceStack OrmLite bind variables appears to be hurting performance

I appears that using bind variables in my queries is hurting performance, some examples by as much as a factor of 5. The following example takes on average about 0.5 seconds to complete.
string strId = "abcd";
using (var db = _conn.OpenDbConnection())
{
var sql = "SELECT count(*) FROM table WHERE idNum= :ID";
var r = db.QueryScalar<int>(sql, new { ID = strID.ToUpper() });
return r >= 1;
}
When I run the following code it takes around 0.1 seconds to complete.
string strId = "abcd";
using (var db = _conn.OpenDbConnection())
{
var sql = string.Format("SELECT count(*) FROM table WHERE idNum= '{0}'", strID.ToUpper());
var r = db.QueryScalar<int>(sql);
return r >= 1;
}
Am I using something incorrectly here that is causing the performance issue?
This is in C# against an Oracle database using version 3.9.71.0 of ServiceStack.OrmLite

Categories

Resources