C# SqlCommand returns 0 - c#

I've created a SQL query that I execute with the following command, and it returns the correct number of entries but these contains all 0:
If I run the same SQL command in my Management Studio, it works correctly.
I also tried it with a Linq statement and it works also correctly:
I hope you guys can help me to solve the problem.

You shouldn't be projecting into a List<T> - the ToList() does that. Basically, simplify:
var data = dbContext.Database.SqlQuery<Tuple<DateTime, string, string>>(...).ToList();
It might also work with value-tuples:
var data = dbContext.Database.SqlQuery<(DateTime, string, string)>(...).ToList();
which would also allow you to conceptually name them:
var data = dbContext.Database.SqlQuery<(DateTime Datum, string Text, string Bemerkung)>
(...).ToList();
Note: concatenating filter is almost certainly a SQL injection vulnerability; if looks like you should be using a SQL parameter there instead.
#Evk notes that EF might not support column-wise binding of tuples. If that is the case, then your best bet would be to create a POCO that matches the column definitions:
class Foo // rename me to something meaningful
{
// note: there may be custom attributes you can use
// to make these names less ugly, i.e.
// [Column("TEXT")] on a property called Text
public DateTime RMA_DATUM {get;set;}
public string TEXT {get;set;}
public string BEMERKUNG {get;set;}
}
and use SqlQuery<Foo>.

Related

.NET Core API - parse array in query string for HTTP GET [duplicate]

I want to do this, but I want to also be able to pass in arrays into the query string. I've tried things like:
http://www.sitename.com/route?arr[]=this&arr[]=that
http://www.sitename.com/route?arr[]=this&that
http://www.sitename.com/route?arr[0]=this&arr[1]=that
http://www.sitename.com/route?arr0=this&arr1=that
http://www.sitename.com/route?arr=this&arr=that
And my route in the C# code looks like this:
[Route("route")]
[HttpGet]
public void DoSomething(string[] values)
{
// ...
}
But in all of these cases, values is always null when it gets to the C# code. What do I need my query string to be to pass an array of strings?
Use a parameter name in the query string. If you have an action:
public void DoSomething(string[] values)
Then use values in the query string to pass an array to a server:
?values=this&values=that
Delimited string is not the standard. Think also about the client if you support swagger or other generators.
For those who wonder about .net core 2.1 bug which receives an empty list, the work around is here: https://github.com/aspnet/Mvc/issues/7712#issuecomment-397003420
It needs a name parameter on FromQuery
[FromQuery(Name = "employeeNumbers")] List<string> employeeNumbers
I have found a solution. For example, if you have a query like this:
http://www.sitename.com/route?arr[]=this&arr[]=that
You must define in parameter as [FromQuery(Name = "arr[]")]. The name of parameter must include square brackets. As result we can see:
public void DoSomething([FromQuery(Name = "arr[]")] string[] arr)
I had to do something similar to this, but instead of strings, i used a list of long to pass some id for a search. Using a multiple select option, the chosen values are sent to the method (via get) like this:
[HttpGet("[action]")]
public IActionResult Search(List<long> idsSelected)
{
///do stuff here
}
I also use Route("[controller]") before the class declaration. Works just fine, but the list of items is broken into multiple parameters in the url, as shown below.
http://localhost:5000/Search/idsSelected=1&idsSelected=2
I found two problems in your question:
Your query has parameters named arr while you Contrller's Action has values.
I don't know why, but you gotta name your parameter (as answered here) so the Asp .NET ModelBinder can work as expected. Like this:
public void DoSomething([FromQuery(Name = "values")] string[] values)
After doing that, everything should work as expected.
Given:
public ValuesController
{
public IACtionResult Get([FromUri]string[] arr)
{
Return Ok(arr.Length);
}
}
The following request will work:
GET /api/values/?arr[0]=a&arr[1]=b&arr[2]=c
In the end, I just passed in a single delimited string, then used string.Split to separate on the server side. Not the prettiest solution, but it works. Until someone comes up with a better answer, this is all I got. I should reiterate that I'm using .NET Core, and these query strings are framework specific.
Update: An (arguable) benefit of this approach is that you pass the values together (e.g. arr=value1,value2) instead of repeating the key (arr=value1&arr=value2).
I had the same problem with .NET Core 3, while trying to pass in a string Array. I solved it by passing in the query parameter as a temporary json string. I then deserialized the string to the resulting array using Newtonsoft's Json package
using Newtonsoft.Json;
public IActionResult Get([FromQuery(Name = "array")] string arrayJson)
{
List<string> array = JsonConvert.DeserializeObject<List<string>>(arrayJson);
}

How to make a formatted string property into a linq-to-entity friendly expression?

In a recent EF Code First project we were attempting to optimize some Linq queries using different techniques (don't worry its not premature). One common way to optimize a linq query is to convert more of the expression from Linq-to-Objects to almost all Linq-to-Entities side, which is generally faster than mixing Linq-to-Objects and Linq-to-Entities with lazy loading.
I've read how to create linq expressions for most queries that are translatable to Linq-To-Entities, but I'm not sure how to do this with the object initializer syntax.
Take this example:
return results.Select(x => new { Name = x.FullName });
From the falling example Person class:
public class Person
{
public string FullName
{
get { return FirstName + " " + LastName; }
}
public string FirstName { get; set; }
public string LastName { get; set; }
}
Now I can make the first expression into a Linq-to-Entity friendly expression by converting it to:
return results.Select(x => new { Name = x.FirstName + " " + x.LastName});
But this kind of sucks bad because I'm duplicating the logic for the FullName. Now you can say this doesn't matter for such a trivial example, but its not hard to imagine a case with a much more complex read-only property.
Anyway I'm trying to figure out if there is a way to do something like this:
return results.Select(x => new { Name = Person.FullNameExpression(x) });
Can anyone tell me if something like this is possible in Linq-to-entities, without using Linq-to-objects?
If this isn't possible, what's the closest I can get to preventing from repeating the logic for readonly properties on my entites?
Anyway I'm trying to figure out if there is a way to do something like this:
Easy way out:
You simply can't. If you want the logic to only exist in the single location, then it can only run in a single location. As a read-only property on a .Net class means it can only run as a local object. If you don't want that logic there, then you have to send it to the (sql) server.
The Road less traveled:
I believe you could technically create an expression that could run on either a local Person or a server side anonymous type, but I personally think that maybe overkill and not exactly easily maintainable code unless you're familiar with expression trees.
While using the 'database first' approach, I usually place the calculated/readonly properties in a partial class. These calculated fields/properties are simply not mapped, since they do not exist in my database table. So when I fetch persons, which populates first- and lastname, a call to the fullname property on the person class would construct the value on the fly. Exactly like in your example.
I am not too comfortable with code first, but you could perfectly setup readonly properties on your person class too. The only thing you need to do is to tell EF that this property is unmapped, either via the unmapped attribute or via DbModelBuilder.Ignore.
Then there is no need duplicate the fullname logic. After fetching persons from the database, fullname would be available via accessing the property.
results.Select(person => person.Fullname)

Dapper mapping String parameter as AnsiString

I need to pass parameters to SQL statement, with Firebird ADO everything works well, but with InterBase ADO there is a problem.
My code:
result = conn.Query<DestClass>(sqlCmd, new
{
stringParam = stringVal,
intParam1 = intVal1,
intParam2 = intVal2
}).Single();
With that I've got FormatException, but when I define parameters with DynamicParameters and setting DbType.AnsiString for stringParam, SQL works well. But I've got many places in my code when I need to pass string and I don't want to change this in all places.
Then I found that I can use Dapper.SqlMapper.AddTypeMap(typeof(String), DbType.AnsiString);
but I can't. I've got Common Language Runtime detected an invalid program.
How to resolve this issue?
EDIT
It looks like problem is solved in Dapper v1.22.
There is a proposal to add an assembly-level attribute of the form:
[assembly:SomeName(blah)]
that would control the default string type for all types coming from that assembly. This would probably achieve most of what you need (although it would push the swing the other way, so you need to tell the other uses what to do). I am currently very actively hacking dapper, so I would expect this to materialize in the short term.
Note that you do not need to use DynamicParameters; you can also use:
stringParam = new DbString { Value = stringVal, IsAnsi = true }

Do not want to make multiple overloaded functions. Query Parameter Problem

there can be variable number of params being sent through a query string. in my form the query sends a few params that may not always be filled i.e. they will be sent as id="". this means that the function being used in my TableAdapter will bring the wrong result if one param is not coming in. i.e. it recieved 7 params whereas it was expecting 8 (or the 8th will be NULL).
The only workaround i can think is to make overloaded functions. but that means i will have to make 64 overloaded functions (for 8 params). Too much work, which makes me think that there maybe some other way i could get the job done without making 64 functions.
Is there any?
Working on ASP.NET with MSSQL
There is one work around we are using and It works perfectly for us.
You don't need to make any overload functions. You can pass all the parameter's values and If there is an empty value you can simply pass '%' and you don't need to do anything with the query either. Here is an example of an SQL Query:
Select * from Student where ID = 5 AND RollNo = '%' AND CourseID = '%'
If you check the above query in SQL server it will give you correct result.
Note: I have not tested this with TableAdapter, But I am sure it will work.
64 overloaded functions clearly isn't a workable solution. It's probably time to look at your WorkTable adapter code as it sounds like it isn't handling exceptional values very gracefully.
I would go with ashelvey's suggestion of one method with 8 parameters and make sure the handling code is robust enough to deal with null values or empty strings.
Introduce an object that is specifically for the parameters.
public void DoWork(params OperationArgs args[]) { /* code */ }
class OperationArgs {
public int? Id { get; set; }
public string Keywords { get; set; }
// etc
}

LINQ to SQL - Format a string before saving?

I'm trying to convert an existing (non-LINQ to SQL) class into a LINQ to SQL entity class which has an existing (db column) property like:
public string MyString
{
get { return myString; }
set { myString = FormatMyString(value); }
}
Is there a way to do this sort of processing on the value of entity class property before saving?
Should I use some sort of an entity-level saving event in which to do my formatting (if that will even work)?
I know LINQ to SQL provides validation and there are generated On...Changing() partial methods which provide access to the new value, by value (not by ref), but none of those methods seem to provide a way to actually modify/format the value while it is being set.
Thank you for your help.
What about using On...Changed()? It fires after the property value has changed. There you can check its value and update it using the FormatString.

Categories

Resources