Auto-magically add MySQL parameters in C# - c#

At the moment, I'm creating a new method for each mysql query with parameters I want to get performed.
An example:
public DataTable RetreiveAllLinks(int id, int categoryid)
{
const string request =
#"
SELECT *
FROM links
WHERE id=?id,categoryid=?categoryid
ORDER by id DESC
";
using (var query = new MySqlCommand(request))
{
query.Parameters.AddWithValue("?id", id);
query.Parameters.AddWithValue("?categoryid", categoryid);
return _connection.RetreiveData(query);
}
}
This is really getting on my nerves, because I always end up with 10-30 queries, when two queries can do it for me, a simple method for retrieving non-parameter query, and a method for parameters. For example
public DataTable NonParameterCommand(string r)
{
var request = r;
using (var query = new MySqlCommand(request))
{
return _connection.RetreiveData(query);
}
}
What I want to do, is some regex'ing, where i would say e.g.
var pPattern = "^[\\?][\\w]";
and then a method with request and a list as parameters, and the list should be in the same order as the request parameters. So if the request is
`"SELECT * FROM test WHERE id=?id,categoryid=?categoryid"`
then my list would look like
var _dictionary = new Dictionary<string, string>();
_dictionary.Add(_parameter, _value);
and my method
ParameterCommand(string r, Dictionary dic)
but how exactly?

If you are using a dictionary, then the key would already be the parameter name. Why parse the query to extract them?
You could do:
public DataTable CommandWithParams(string sql, Dictionary<string, object> parameters)
{
using (var query = new MySqlCommand(sql))
{
foreach (var param in parameters)
{
query.Parameters.AddWithValue(param.Key, param.Value);
}
return _connection.RetreiveData(query);
}
}
Calling it:
var parameters = new Dictionary<string, object>()
{
{ "?param1", value1 },
{ "?param2", value2 }
};
var result = CommandWithParams(query, parameters);
But maybe you'd like to use a List instead of a Dictionary?
(I wouldn't recommend it, passing the parameters values based on their position would be error-prone)

Related

C# to Sort by Last Created (oldest record) & Limit results to 20 records from DynamoDB Table

How to apply Sort by Last Created (oldest record) & Limit results to 20 records from DynamoDB Table using BatchGetItemAsync Method. Thanks in Advance.
var table = Table.LoadTable(client, TableName);
var request = new BatchGetItemRequest
{
RequestItems = new Dictionary<string, KeysAndAttributes>()
{
{ TableName,
new KeysAndAttributes
{
AttributesToGet = new List<string> { "ID", "Status", "Date" },
Keys = new List<Dictionary<string, AttributeValue>>()
{
new Dictionary<string, AttributeValue>()
{
{ "Status", new AttributeValue { S = "Accepted" } }
}
}
}
}
}
};
var response = await client.BatchGetItemAsync(request);
var results = response.Responses;
var result = results[fullTableName];
There isn't a way to do what you're asking for with BatchGetItemAsync. That call is to get specific records, when you know the specific keys you are looking for. You'll need to use a query to do this, and you'll want to get your data in a structure that supports this access pattern. There was a really great session on DynamoDB access patterns at re:Invent 2018. I suggest watching it: https://www.youtube.com/watch?v=HaEPXoXVf2k

Finding values in a string:string dictionary where a given filter string is a subset of the key string

I have a Dictionary<string, string> object where values are stored that look like this:
examplePlanet : defaultText0
examplePlanet* : defaultText1
examplePlanet** : defaultText2
examplePlanetSpecificlocationA : specificAText0
examplePlanetSpecificlocationA* : specificAText1
examplePlanetSpecificlocationB : specificBText
And I have a string filter that matches one of these keys or is a subset of a key.
This filter has the form planetLocation, which can be split into planet and location.
My goal is to create a list of values where the filter is matched in this way: if planetLocation exists in the dictionary, add its value, and all values where the key matches but has extra *'s, to a list.
If planetLocation does not exist, only add values where the key matches the planet part of the filter (with possible extra *'s).
Basically, I want all values where the filter matches the key as much as possible.
Examples:
examplePlanetSpecificlocationA gives [specificAText0, specificAText1]
examplePlanetSpecificlocationB gives [specificBText]
examplePlanetSpecificlocationC gives [defaultText0, defaultText1, defaultText2]
I have already tried (among other things that didn't work) this:
private List<string> filteredResults;
///<summary>Filters dictionaries and returns a list of values</summary>
private List<string> GetFilteredResults(Dictionary<string, string> inputdictionary, string filter)
{
List<string> _filteredResults = new List<string>();
foreach (KeyValuePair<string, string> entry in inputdictionary)
{
if (entry.Key.Contains(filter))
{
_filteredResults.Add(entry.Value);
}
}
return _filteredResults;
}
public void main()
{
//stuff happens here that assigns a value to filterPlanet and filterLocation
filteredResults = new List<string>();
filteredResults = GetFilteredResults(exampledictionary, filterPlanet + filterLocation);
if (filteredResults.Count == 0)
{
filteredResults = GetFilteredResults(exampledictionary, filterPlanet);
}
//do stuff with the filtered results
}
This almost worked, but returns all values where the key contains filterPlanet and not just filterPlanet itself plus possible *'s. I'm not sure how to make this function do what I want, and even if it somehow works I'm sure there is a more efficient way of filtering than this. Could you please help me here?
I wouldn't use the *'s as a way of differentiating multiple values for the same key, and I'd keep filterPlanet and filterLocation separate. That way you can use a simple O(1) dictionary lookup, rather than iterating across all keys, doing substring searching, etc.
public class PlanetFilterer
{
private readonly Dictionary<string, List<string>> lookup = new Dictionary<string, List<string>>();
public PlanetFilterer(IEnumerable<(string filter, string value)> filters)
{
foreach (var (filter, value) in filters)
{
var filterWithoutStars = filter.TrimEnd('*');
if (!lookup.TryGetValue(filterWithoutStars, out var values))
{
values = new List<string>();
lookup[filterWithoutStars] = values;
}
values.Add(value);
}
}
public IReadOnlyList<string> Lookup(string planet, string location)
{
List<string> results;
if (lookup.TryGetValue(planet + location, out results))
{
return results;
}
if (lookup.TryGetValue(planet, out results))
{
return results;
}
return Array.Empty<string>();
}
}
Usage:
var filters = new[]
{
("examplePlanet", "defaultText0"),
("examplePlanet*", "defaultText1"),
("examplePlanet**", "defaultText2"),
("examplePlanetSpecificlocationA", "specificAText0"),
("examplePlanetSpecificlocationA*", "specificAText1"),
("examplePlanetSpecificlocationB", "specificBText"),
};
var filterer = new PlanetFilterer(filters);
Console.WriteLine(string.Join(", ", filterer.Lookup("examplePlanet", "SpecificlocationA")));
Console.WriteLine(string.Join(", ", filterer.Lookup("examplePlanet", "SpecificlocationB")));
Console.WriteLine(string.Join(", ", filterer.Lookup("examplePlanet", "SpecificlocationC")));
Try it online

How do I query a SQL Server database with a list of parameters in Dapper?

I have a list of objects with various properties. I want to query a database using these properties and get a result list back.
This is what I've tried:
public async Task<IEnumerable<Animal>> GetAnimalsFromAttributesAsync(IEnumerable<AnimalInfo> attributeSets)
{
using (var myDB = new SqlConnection(connectionString))
{
await myDB.OpenAsync();
var results = new List<Animal>();
foreach (var attributeSet in attributeSets)
{
var sql = #"select AnimalID, AnimalTypeID, AnimalColor
from Animals
where AnimalTypeID = #AnimalTypeID
and AnimalColorID = #AnimalColorID";
var result = myDB.Query<Animal>(sql, attributeSet);
results.AddRange(result);
}
return results
}
}
This works ok for small numbers of properties. But if I have a lot of properties, then I get this error:
Error: The incoming request has too many parameters. The server supports a maximum of 2100 parameters. Reduce the number of parameters and resend the request.
Is there a better way to do this?
Thanks to #MarcGravell's suggestion, I decided to rewrite my query as a TVP query.
SQL:
create type AnimalInfo as table
(
AnimalTypeID int,
AnimalColorID int
)
go
C#:
public async Task<IEnumerable<Animal>> GetAnimalsFromAttributesAsync(DataTable attributeSets)
{
using (var myDB = new SqlConnection(connectionString))
{
await myDB.OpenAsync();
var sql = #"select AnimalID, AnimalTypeID, AnimalColor
from Animals
inner join #animalInfos animalInfos on
animalInfos.AnimalColorID = Animals.ColorID
and
animalInfos.AnimalTypeID = Animals.AnimalTypeID";
var result = await myDB.QueryAsync<Animal>(sql, new { animalInfos = attributeSets.AsTableValuedParameter("AnimalInfo") };
return result;
}
}

How to save query into dictionary in c#?

I am using Visual Studio 2012 and C#. I have a problem: I want to collect all results of a SQL query into dictionary.
This is my code:
Dictionary<int,List<string>> dic = new Dictionary<int, List<string>>();
string query = "select request_number, service_category ,service_type from enugro.enugro_service_requests_info;";
MySqlConnection connec = new MySqlConnection(strcon);
connec.Open();
MySqlCommand cmd = new MySqlCommand(query,connec);
MySqlDataReader reader = cmd.ExecuteReader();
while(reader.Read())
{
dic.Add((int)reader["request_number"], { reader["service_category"], reader["service_type"] });
}
// display result
foreach(var disp in dic)
{
MessageBox.Show(disp.Key.ToString()+"= "+disp.Value.ToString());
}
As you can see my SQL query returns 3 columns to be retrieved and to store into dictionary. Could you help me?
Since the type of the dictionary values is List<string>, then you need to create a new list for each row and add it to the dictionary like this:
dic
.Add(
(int)reader["request_number"],
new List<string>
{
reader["service_category"].ToString(),
reader["service_type"].ToString()
});
Consider creating a class to hold the information that you want from each row and use it as the type for the dictionary values. Such class would look something like this:
public class MyValue
{
public string ServiceCategory {get;set;}
public string ServiceType {get;set;}
}
Then you can have your dictionary be of type Dictionary<int, MyValue> which will allow you to do this:
dic
.Add(
(int)reader["request_number"],
new MyValue
{
ServiceCategory = reader["service_category"].ToString(),
ServiceType = reader["service_type"].ToString()
});
Why would you do that? You can create DTO (data transfer object) with properties according to column names in database, and bind query result to it. Then you can return list of DTO objects. It would be better solution, then complicating with dictionary.

Convert object[] "list" from SQL query into string[] "test"

I wanna convert an object Array called "list" into a string Array called "test".
Attached the code.
The Problem is, the function is returning "System.Collections.Generic.Dic..." and not the strings in SQL database.
Thanks..
Code:
public string[] ListMethod(string command)
{
MySqlCommand comm = new MySqlCommand(command, conn);
MySqlDataReader commreader;
commreader = comm.ExecuteReader();
var list = new List<IDictionary<string, object>>();
while (commreader.Read())
{
var record = new Dictionary<string, object>();
for (int i = 0; i < commreader.FieldCount; i++)
{
var key = commreader.GetName(i);
var value = commreader[i];
record.Add(key, value);
}
list.Add(record);
}
string[] test = ((IEnumerable)list).Cast<object>().Select(x => x.ToString()).ToArray();
return test;
}
Lets look at your LINQ Query:
string[] test = ((IEnumerable)list).Cast<object>().Select(x => x.ToString()).ToArray();
What you are saying to the compiler here is:
Cast all objects in the list of dictionaries to object, and then execute to ToString() method of each object (which by default always prints the name of the class) and set it to an array (The cast do IEnumerable is redundant since List implements that interface anyway.
What you actually need to do is:
var test = list.Select(x => x.Values.ToString()).ToArray();
assuming all your values in the IDictionary are actually strings, this will fetch them for you.

Categories