MonoTouch: Can't create DbParameterCollection? - c#

I'm a vb.net guy trying to figure out MonoTouch c#.
I made this data helper:
public static void ExecuteCommand (SqliteConnection cnn, string command, System.Data.Common.DbParameterCollection parameters)
{
using (var c = cnn.CreateCommand()) {
c.CommandText = command;
c.CommandType = CommandType.Text;
foreach (var p in parameters)
{
c.Parameters.Add (p);
}
c.ExecuteNonQuery ();
}
}
And now I want to call the ExecuteCommand...
var parameters = new System.Data.Common.DbParameterCollection();
parameters.Add("#1", DbType.String).Value = "test";
DataConnection.ExecuteCommand ("INSERT INTO mytest (name) VALUES (#)", parameters);
But MonoTouch says...
var parameters = new System.Data.Common.DbParameterCollection(); <-- "Cannot create an instance of the abstract class or interface 'System.Data.Common.DbParameterCollection'"
parameters.Add("#1", DbType.String).Value = "test"; <-- "A local variable 'parameters' cannot be used before it is declared."
I'm sure the answer is pretty easy, but comming from a VB.Net world, this is not obvious to me.

System.Data.Common.DbParameterCollection is abstract as such you cannot create it. You should be creating a (concrete( collection that inherits from it. In SQLite case it would be Mono.Data.Sqlite.SqliteParameterCollection.
Your second error is likely related to the first, since parameters could not be compiled correctly.

Related

c# How to create a Method on a Method, or Method Chain

I have created a simplified SQL Data class, and a class method for returning a ready to use resultset:
public SQL_Data(string database) {
string ConnectionString = GetConnectionString(database);
cn = new SqlConnection(ConnectionString);
try {
cn.Open();
} catch (Exception e) {
Log.Write(e);
throw;
}
}
public SqlDataReader DBReader(string query) {
try {
using (SqlCommand cmd = new SqlCommand(query, this.cn)) {
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
} catch {
Log.Write("SQL Error with either Connection String:\n" + cn + " \nor Query:\n" + query);
throw;
}
}
(I catch any errors, log them, and then catch the error higher up the chain. Also, I did not include the ConnectionString() code for brevity. It just returns the requested connection string. That's all.)
This all works just fine, and with a single line of code, I'm ready to .Read() rows.
SqlDataReader rs = new SQL_Data("MyDatabase").DBReader(#"SELECT * FROM Employees");
while (rs.Read()) {
// code
}
rs.Close();
I want to expand this and add a .ColumnReader() method that I want to chain to .DBReader() like this:
string empID = new SQL_Data("MyDatabase").DBReader(#"SELECT * FROM Employees).ColumnReader("EmpID");
I attempted this by adding a .ColumnReader() method, but it ends up being a method of SQL_Data() class directly, not a member or extension of .DBReader(). I also tried adding the .ColumnReader() inside the .DBReader() (like a "closure"), but that didn't work either.
Can this be done?
This ended up working for me:
public static class SQLExtentions {
public static dynamic ColumnReader(this SqlDataReader rs, string colName) {
return rs[colName];
}
}
I will have to expand on it a bit to add some error checking, and perhaps return more than just the dynamic value - like return an object with the value and it's SQL data type. But Paul and Bagus' comments got me on the right track.

C# Converting a var/string to action

My command system works off a database where the entire command is stored.
In the Command creation, the
.SetAction((t, m, c) => { //code });
is what the command actually does.
Pulling from the db, this comes in as a var.
How would I go about converting this to actual code for the Action to actually handle?
Reading through a couple pages from Google leaves me to believe I'll need to use Reflection which I've only touched on with Interfaces.
Snippet of the SetAction
public Command SetAction(Action<string, Message, DiscordClient> action)
{
this.action = action;
return this;
}
The code I am using looks like this:
using (var command = sql.CreateCommand())
{
command.CommandText = "SELECT * FROM commands";
using (var reader = command.ExecuteReader())
{
var actionCol = reader.GetOrdinal("action");
while (reader.Read())
{
var action = reader.GetValue(acionCol);
cm.AddCommand(new Command()
.SetAction((t, m, c,) => { }));
)
}
}

C# Referring to the current form through a static method

I'm working on a method that is static, and returns a value off a WinForm, it spawns the new form on a button click, and upon hitting the submit or cancel buttons it throws back its value.
The issue is, I cant refer to a combobox control on my form to populate it with the results of my sqlreader.
I have read suggestions that I use a wrapper that looks akin to
public ComboBox comboHolder { get return this.foo }
however I can't seem to refer to it either. Any suggestions to remedy this ?
Full code
public ComboBox comboboxWrapper
{
get { return this.comboUsernames; }
}
public static string SelectProfile()
{
Form selectProfile = new Select_Profile();
selectProfile.ShowDialog();
SqlConnection connection = new SqlConnection(#"Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Users.mdf;Integrated Security=True;Connect Timeout=30");
connection.Open();
SqlCommand command = new SqlCommand("SelectAllUsers", connection);
SqlDataReader usersReader = command.ExecuteReader();
List<string> accountNames = new List<string>();
while (usersReader.Read())
{
accountNames.Add((string)usersReader["Username"]);
}
//populate the combo box
foreach (string s in accountNames)
{
//I'd like to call comboboxWrapper here.
}
//set the combo box to have a default item
// combo.SelectedIndex = 0;
}
Also, this is a work in progress, I realize I should have some try, catch and a finally statement, other than that i'm open to any suggestions for code improvement.
Thanks!
I would suggest just not making the method static. But if you really need to for some reason, you could pass a reference to the form into your static method, e.g.:
SelectProfile(Form myForm)
Then you would be able to use it inside the method like this:
foreach (string s in accountNames)
{
// e.g myForm.comboboxWrapper
}
your static method need object of class for that you have to pass object of class where comboboxwrapper defined
public static string SelectProfile(ClassobjectofCoboboxWrapper obj)
{
obj.comboboxWrapper;
}
Call to this method from outside
SelectProfile(new ClassobjectofCoboboxWrapper())
Note:
As static method are not related to instace of object its related to class. So to refer element in static method which are not static you either need to create object of refering class or you need to pass object of class your want to refer.
This is your form instance:
Form selectProfile = new Select_Profile();
So you'd call comboboxWrapper on that instance:
selectProfile.comboboxWrapper
Though first you'll need to change its type, since Form doesn't have a member called comboboxWrapper. Declare it like this instead:
Select_Profile selectProfile = new Select_Profile();
or simply:
var selectProfile = new Select_Profile();
Even though the comboboxWrapper member is defined outside the static method, it's inside the form instance. A static member has no default notion of a particular instance and needs to be provided with one. Or, in this case, internally creates one.
First, decompose your solution: just don't cram database and UI into single method. Next think over what your method is supposed to return as a String:
public static IEnumerable<String> AccountNames() {
//TODO: Move it into Settings/Config...
String connectionString = #"Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Users.mdf;Integrated Security=True;Connect Timeout=30";
// Dispose (via using) all Disposable...
using (SqlConnection connection = new SqlConnection(connectionString)) {
connection.Open();
// Dispose: prevent resource leakage...
using (SqlCommand command = new SqlCommand("SelectAllUsers", connection)) {
using (SqlDataReader usersReader = command.ExecuteReader()) {
while (usersReader.Read())
yield return (string)usersReader["Username"];
}
}
}
}
// returns selected profile
// or null if no profile was seelcted
public static string SelectProfile() {
// var: You need Select_Profile, not just a Form, right?
// again (using): don't forget to clear up the resources
using (var selectProfile = new Select_Profile()) {
// Providing that comboboxWrapper is public (bad practice)
// or SelectProfile() is implemented within Select_Profile class (good one)
selectProfile.comboboxWrapper.Items.AddRange(AccountNames());
if (selectProfile.comboboxWrapper.Items.Count > 0)
selectProfile.comboboxWrapper.SelectedIndex = 0;
if (selectProfile.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
if (selectProfile.comboboxWrapper.SelectedIndex < 0)
return null; // No item to select
else
selectProfile.comboboxWrapper.SelectedItem.ToString();
}
else
return null; // Just closed
}
}

How do I refactor this C# SQL query to do a unit test?

I have this code that queries a database. I want to put the actual database code into a separate class so I can reuse it in other places. This will leave just the actual read of the PassResult value so I can make a Unit Test of the code without having the SQL code running. I am having trouble finding references on how to make this kind of code Unit Testable. Could someone help out?
using System;
using System.Data;
using System.Data.SqlClient;
namespace CS_UI_Final_Inspection
{
public class CalibrationTestCheck
{
// declare the variables
private bool _calibrationTestPass = false;
private string _connectionString = string.Empty;
public bool CheckCalibrationTestResults(string serialNumber, IDeviceInfo deviceInfo, string mapID)
{
// get database location
DhrLocationPull dhrLocation = new DhrLocationPull();
_connectionString = dhrLocation.PullDhrLocation();
// build the query
SqlConnection calibrationCheckConnection = new SqlConnection(_connectionString);
SqlCommand calibrationCheckCommand = new SqlCommand("[MfgFloor].[GetLatestTestResultsForDeviceByTestType]",
calibrationCheckConnection);
// build the stored proc
calibrationCheckCommand.CommandType = CommandType.StoredProcedure;
calibrationCheckCommand.Parameters.Add(new SqlParameter("#SerialNumber", serialNumber));
calibrationCheckCommand.Parameters.Add(new SqlParameter("#DeviceTypeID", mapID));
calibrationCheckCommand.Parameters.Add(new SqlParameter("#TestDataMapTypeID", "C"));
calibrationCheckCommand.Connection.Open();
SqlDataReader calibrationCheckReader = calibrationCheckCommand.ExecuteReader();
// is there data?
if (calibrationCheckReader.HasRows)
{
// read the data
calibrationCheckReader.Read();
try
{
_calibrationTestPass = (bool) calibrationCheckReader["PassResult"];
}
catch (InvalidOperationException)
{
// means last element was not filled in
}
finally
{
// close refs
calibrationCheckReader.Close();
calibrationCheckCommand.Connection.Close();
calibrationCheckConnection.Close();
calibrationCheckReader.Dispose();
calibrationCheckCommand.Dispose();
calibrationCheckConnection.Dispose();
}
}
return _calibrationTestPass;
}
}
}
create an interface and implement it.
move all references to be tested to use the interface (exposing any methods/properties required through the interface)
have the constructor or method being tested take the interface as a parameter.
Roy Oscherov is a good resource on this. Roy Oscherov wrote a great book called "The art of unit testing". Roy's website can be found here: http://osherove.com/

braces and curly brackets when generating interface with codeDom

I am using codeDom to generate an interface and I am getting braces and curly brackets in places I don't want. I am decorating a method with [OperationContract()] but I don't want the braces there. Here is the code I have written
toStringMethod.CustomAttributes.Add(new CodeAttributeDeclaration("OperationContract"));
Also, the methods that are generated have curly brackets added. I don't want that. Since this is an interface, I want just a semicolon. Here is what it looks like now.
[OperationContract()]
System.Collections.Generic.List<Aristotle.P6.Model.KeyIssue.Issue> GetAllIssues()
{
}
Below lies the majority of the code I have written;
foreach (var dll in dlls)
{
Assembly assembly = Assembly.LoadFrom(dll);
foreach (var type in assembly.ExportedTypes)
{
var methodInfo = type.GetMethods();
CodeCompileUnit targetUnit;
CodeTypeDeclaration targetClass;
targetUnit = new CodeCompileUnit();
CodeNamespace samples = new CodeNamespace("CodeDOMSample");
samples.Imports.Add(new CodeNamespaceImport("System"));
targetClass = new CodeTypeDeclaration("CodeDOMCreatedClass");
targetClass.IsClass = true;
targetClass.TypeAttributes =
TypeAttributes.Public | TypeAttributes.Sealed;
samples.Types.Add(targetClass);
targetUnit.Namespaces.Add(samples);
foreach (var method in methodInfo)
{
CodeMemberMethod toStringMethod = new CodeMemberMethod();
toStringMethod.Attributes =
MemberAttributes.AccessMask;
toStringMethod.Name = method.Name;
toStringMethod.CustomAttributes.Add(new CodeAttributeDeclaration("OperationContract"));
foreach (var item in method.GetParameters())
{
toStringMethod.Parameters.Add(new CodeParameterDeclarationExpression(item.ParameterType, item.Name));
}
toStringMethod.ReturnType =
new CodeTypeReference(method.ReturnType);
targetClass.Members.Add(toStringMethod);
}
Program program = new Program();
program.GenerateCSharpCode(type.Name, targetUnit);
}
}
Update
This is what my GenerateCSharpCode method looks like:
public void GenerateCSharpCode(string fileName, CodeCompileUnit targetUnit)
{
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
CodeGeneratorOptions options = new CodeGeneratorOptions();
options.BracingStyle = "C";
using (StreamWriter sourceWriter = new StreamWriter(fileName))
{
provider.GenerateCodeFromCompileUnit(
targetUnit, sourceWriter, options);
}
}
When you use CodeDom, I understand you have some options on how code is created. You have to use the CodeGeneratorOptions and set the BracingStyle = "C"; if you want to change the default behavior.
Take a look on the Examples section on the following article.
http://msdn.microsoft.com/en-us/library/system.codedom.compiler.codegeneratoroptions(v=vs.110).aspx
Hope this helps.
EDIT
Are you generated code creating classes or interfaces? I understand you want interfaces, so you should replace the IsClass = true to IsInterface = true.
Take a look at this question: how to create an interface method with CodeDom

Categories

Resources