I'm trying to get data from an Azure SQL Server. I've Been able to get the data through this method:
let db = dbSchema.GetDataContext()
let serviceType = db.table
serviceType
I then go on to do some type casting where I get the actual data. But as my program has progressed I need a new way of getting the data.
I'm able to get a list of column names with this piece of code:
let columnList = (new SqlCommandProvider<"select * from Information_schema.Columns where table_name = #tableName",connectionString).Execute(tableName)
I'm wondering if there's a similar way to get the data.
I've tried:
let data = (new SqlCommandProvider<"select * from #tableName",connectionstring).Execute(tableName)
But I get this error: "Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of object. This may allow the lookup to be resolved."
I came up with this.
let GetData (tableName : string) =
let cn = new SqlConnection(connectionstring)
cn.Open()
let sQL = "select * from [" + tableName + "]"
let db = new SqlCommand(sQL, cn)
db.ExecuteReader()
From here you can access your data. So assign db.ExecuteReader() to a variable then...
let dataSource = db.ExecuteReader()
let mutable tableData = List.empty
while dataSource.Read() do
let rowLength = dataSource.FieldCount
let rowData = Array.zeroCreate(rowLength)
for i = 0 to dataSource.FieldCount-1 do
rowData.SetValue(dataSource.GetValue(i),i)
tableData <- rowData :: tableData
tableData |> List.toArray
This returns all the values in the table
This is one way (using the SqlClient type provider) to select all data from a table. If your table is too large it will return a lot. So I just select the Top 1000 rows. Replace tablenn with your choice of table name. You can parametrize the columns, but if you need to put the table name itself as a parameter you might need to use a Stored Procedure that takes a Table as a parameter (or use quotations in other type providers).
However, this is a string so it's very easy to build it. Then again, it has to be a literal.
#r #"..\packages\FSharp.Data.SqlClient.1.8.2\lib\net40\FSharp.Data.SqlClient.dll"
open FSharp.Data
open System
[<Literal>]
let connectionString = #"Data Source=(localdb)\MSSQLLocalDB;AttachDbFilename=C:\Users\userName\Documents\Test.sdf.mdf;Integrated Security=True;Connect Timeout=10"
[<Literal>]
let tblnn = "MyBigTable"
[<Literal>]
let qry = "SELECT TOP 1000 * FROM " + tblnn
let cmd = new SqlCommandProvider<qry, connectionString>(connectionString)
cmd.Execute() |> Seq.toArray
You can also use the stock SqlDataConnection type provider. It also makes it easy to select all data from a table.
Related
I have an SQL statement that I'm executing through OleDb, the statement is something like this:
INSERT INTO mytable (name, dept) VALUES (#name, #dept);
I'm adding parameters to the OleDbCommand like this:
OleDbCommand Command = new OleDbCommand();
Command.Connection = Connection;
OleDbParameter Parameter1 = new OleDbParameter();
Parameter1.OleDbType = OleDbType.VarChar;
Parameter1.ParamterName = "#name";
Parameter1.Value = "Bob";
OleDbParameter Parameter2 = new OleDbParameter();
Parameter2.OleDbType = OleDbType.VarChar;
Parameter2.ParamterName = "#dept";
Parameter2.Value = "ADept";
Command.Parameters.Add(Parameter1);
Command.Parameters.Add(Parameter2);
The problem I've got is, if I add the parameters to command the other way round, then the columns are populated with the wrong values (i.e. name is in the dept column and vice versa)
Command.Parameters.Add(Parameter2);
Command.Parameters.Add(Parameter1);
My question is, what is the point of the parameter names if parameters values are just inserted into the table in the order they are added command? The parameter names seems redundant?
The Problem is that OleDb (and Odbc too) does not support named parameters.
It only supports what's called positional parameters.
In other words: The name you give a parameter when adding it to the commands parameters list does not matter. It's only used internally by the OleDbCommand class so it can distinguish and reference the parameters.
What matters is the order in which you add the parameters to the list. It must be the same order as the parameters are referenced in the SQL statement via the question mark character (?).
But here is a solution that allows you to use named parameters in the SQL statement. It basically replaces all parameter references in the SQL statement with question marks and reorders the parameters list accordingly.
It works the same way for the OdbcCommand class, you just need to replace "OleDb" with "Odbc" in the code.
Use the code like this:
command.CommandText = "SELECT * FROM Contact WHERE FirstName = #FirstName";
command.Parameters.AddWithValue("#FirstName", "Mike");
command.ConvertNamedParametersToPositionalParameters();
And here is the code
public static class OleDbCommandExtensions
{
public static void ConvertNamedParametersToPositionalParameters(this OleDbCommand command)
{
//1. Find all occurrences of parameter references in the SQL statement (such as #MyParameter).
//2. Find the corresponding parameter in the commands parameters list.
//3. Add the found parameter to the newParameters list and replace the parameter reference in the SQL with a question mark (?).
//4. Replace the commands parameters list with the newParameters list.
var newParameters = new List<OleDbParameter>();
command.CommandText = Regex.Replace(command.CommandText, "(#\\w*)", match =>
{
var parameter = command.Parameters.OfType<OleDbParameter>().FirstOrDefault(a => a.ParameterName == match.Groups[1].Value);
if (parameter != null)
{
var parameterIndex = newParameters.Count;
var newParameter = command.CreateParameter();
newParameter.OleDbType = parameter.OleDbType;
newParameter.ParameterName = "#parameter" + parameterIndex.ToString();
newParameter.Value = parameter.Value;
newParameters.Add(newParameter);
}
return "?";
});
command.Parameters.Clear();
command.Parameters.AddRange(newParameters.ToArray());
}
}
Parameter NAMES are generic in the SQL support system (i.e. not OleDb specific). Pretty much ONLY OleDb / Odbc do NOT use them. They are there because OleDb is a specific implementation of the generic base classes.
I am new to Power Builder and I would like to ask how can I represent my objects in a table form. For example, given an ArrayList in java I have implemented the code like this:
table = new JTable();
scrollPane.setViewportView(table);
DefaultTableModel tableModel =
new DefaultTableModel(
new String[] {
"ScheduleNo",
"Start Date",
"End Date",
"No of days",
"Principal Expected",
"Interest Expected",
"EMI amount",
"Factor",
"MeanFactor"}
, 0);
for (Schedule s : pf.getSchedules()){
Integer schNo = s.getScheduleNo();
String startDate = df.format(s.getStartDate());
String endDate = df.format(s.getEndDate());
Integer noofdays = s.getNoOfDays();
String prinExp = String.format("%.2f", s.getPrincipalAmt());
String intExp = String.format("%.2f", s.getInterestAmt());
String emi = String.format("%.2f", s.getAmortizedAmount());
String factor = String.format("%.6f", s.getFactor());
String mean = String.format("%.6f", s.getProductByFactor());
Object[]data = {schNo, startDate, endDate, noofdays, prinExp, intExp,
emi, factor, mean};
tableModel.addRow(data);
}
table.setModel(tableModel);
But I cannot find a way to do it in PowerBuilder without having a connection to a database and pick the data from there which is totally not the case.
The data come from an User Object array[] and have exactly the same form like in the Java example above.
Without really knowing what you are trying to accomplish it appears to me that you could use a 'normal' PowerBuilder datawindow but when you define it you make it's datasource as external. This type of datawindow does not require a connection to a database. You define the 'fields' of the datasource as strings, numeric, etc. when you create it.
In code you can create a datawindow (or datastore for that matter) control, assign the external datasource datawindow object to it, insert a row, then populate the fields with data of the corresponding datatype.
Example usage:
datawindow ldw
long llrow
ldw = CREATE datawindow
ldw.dataobject = 'myExternalDatawindowObject'
llrow = ldw.insertrow(0)
ldw.setitem(llrow,'stringcolumn','my example string')
ldw.setitem(llrow,'numericcolumn',1234)
It's been a while since I used PowerBuilder, but IIRC you should be able to use a DataStore without having a database connection.
I am trying to do create a where clause to pass as a parameter to an Oracle command and it's proving to be more difficult than I thought. What I want to do is create a big where query based off user input from our application. That where query is to be the single parameter for the statement and will have multiple AND, OR conditions in it. This code here works however isn't exactly what I require:
string conStr = "User Id=testschema;Password=pass12341;Data Source=orapdex01";
Console.WriteLine("About to connect to Database with Connection String: " + conStr);
OracleConnection con = new OracleConnection(conStr);
con.Open();
Console.WriteLine("Connected to the Database..." + Environment.NewLine + "Press enter to continue");
Console.ReadLine();
// Assume the connection is correct because it works already without the parameterization
String block = "SELECT * FROM TEMP_VIEW WHERE NAME = :1";
// set command to create anonymous PL/SQL block
OracleCommand cmd = new OracleCommand();
cmd.CommandText = block;
cmd.Connection = con;
// since execurting anonymous pl/sql blcok, setting the command type
// as text instead of stored procedure
cmd.CommandType = CommandType.Text;
// Setting Oracle Parameter
// Bind the parameter as OracleDBType.Varchar2
OracleParameter param = cmd.Parameters.Add("whereTxt", OracleDbType.Varchar2);
param.Direction = ParameterDirection.Input;
param.Value = "MY VALUE";
// Get returned values from select statement
OracleDataReader dr = cmd.ExecuteReader();
// Read the identifier for each result and display it
while (dr.Read())
{
Console.WriteLine(dr.GetValue(0));
}
Console.WriteLine("Selected successfully !");
Console.WriteLine("");
Console.WriteLine("***********************************************************");
Console.ReadKey();
If I change the lines below to be the type of result I want then I get an error "ORA-00933: SQL command not properly ended":
String block = "SELECT * FROM TEMP_VIEW :1";
...
...
param.Value = "WHERE NAME = 'MY VALUE' AND ID = 5929";
My question is how do I accomplish adding my big where query dynamically without causing this error?
Sadly there is no easy way to achieve this.
One thing you will need to understand with parameterised SQL in general is that bind parameters can only be used for values, such as strings, numbers or dates. You cannot put bits of SQL in them, such as column names or WHERE clauses.
Once the database has the SQL text, it will attempt to parse it and figure out whether it is valid, and it will do this without taking any look at the bind parameter values. It won't be able to execute the SQL without all of the values.
The SQL string SELECT * FROM TEMP_VIEW :1 can never be valid, as Oracle isn't expecting a value to immediately follow FROM TEMP_VIEW.
You will need to build up your SQL as a string and also build up the list of bind parameters at the same time. If you find that you need to add a condition on the column NAME, you add WHERE NAME = :1 to the SQL string and a parameter with name :1 and the value you wish to add. If you have a second condition to add, you append AND ID = :2 to the SQL string and a parameter with name :2.
Hopefully the following code should explain a little better:
// Initialise SQL string and parameter list.
String sql = "SELECT * FROM DUAL";
var oracleParams = new List<OracleParameter>();
// Build up SQL string and list of parameters.
// (There's only one in this somewhat simplistic example. If you have
// more than one parameter, it might be easier to start the query with
// "SELECT ... FROM some_table WHERE 1=1" and then append
// " AND some_column = :1" or similar. Don't forget to add spaces!)
sql += " WHERE DUMMY = :1";
oracleParams.Add(new OracleParameter(":1", OracleDbType.Varchar2, "X", ParameterDirection.Input));
using (var connection = new OracleConnection() { ConnectionString = "..."})
{
connection.Open();
// Create the command, setting the SQL text and the parameters.
var command = new OracleCommand(sql, connection);
command.Parameters.AddRange(oracleParams.ToArray());
using (OracleDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
// Do stuff with the data read...
}
}
}
I am using LINQ query to fetch the data from database and also doing joins in the LINQ query as,
(
from accountTransaction in AccountTransactions
join xlkpQualifier in Enumerations on
accountTransaction.LkpQualifier.ToString() equals xlkpQualifier.Value
select top accountTransaction)
.Take(10);
I am getting Exception on accountTransaction.LkpQualifier.ToString() that System.ToString() can't be used in LINQ Entities.
But I am getting problem here in conversion to string on Join.
How can I do it?
Until you provide us with some more information on the SQL types of the fields LkpQualifier and xlkpQualifier, I will answer as follows:
You should either (1) change your table data schema and set the same data types or (2) write the raw SQL version of your LINQ query and execute the query
Raw SQL query using EF:
using (var db = new Entities())
{
string myQuery = "SELECT * FROM Table";
var result = new ObjectQuery<DbDataRecord>(myQuery, db);
var resultList = result.ToList();
}
In the raw SQL query itself, you will probably have to use the CAST function with the right type:
CAST(Enumerations.xlkpQualifier AS System.Int32)
Raw SQL query without using EF:
There is also a way to write raw SQL without using EF (useful when your table doesn't have the primary key set and you don't have access to change that):
using (var conn = new SqlConnection(connectionString))
{
conn.Open();
using (var cmd = new SqlCommand())
{
cmd.Connection = conn;
cmd.CommandText = "SELECT * FROM Table";
var result = cmd.ExecuteScalar(); // or other variations
}
}
I am using LINQ to SQL queries to return data in my application. However I find it is now needful for me to return the column Names. Try as I might I have been completely unable to find out how to do this on the internet.
So if my LINQ entity table has the properties (Last_Name, First_name, Middle_Name) I need to return:
Last_name
First_Name
Middle_name
rather than the usual
Smith
John
Joe
You could certainly do it with some LINQ-To-Xml directly against the ".edmx" file or the embedded model resources in the compiled assembly.
The below query gets the field (not column) names. If you need the columns then just change the query to suit.
var edmxNS = XNamespace.Get(#"http://schemas.microsoft.com/ado/2007/06/edmx");
var schemaNS = XNamespace.Get(#"http://schemas.microsoft.com/ado/2006/04/edm");
var xd = XDocument.Load(#"{path}\Model.edmx");
var fields =
from e in xd
.Elements(edmxNS + "Edmx")
.Elements(edmxNS + "Runtime")
.Elements(edmxNS + "ConceptualModels")
.Elements(schemaNS + "Schema")
.Elements(schemaNS + "EntityType")
from p in e
.Elements(schemaNS + "Property")
select new
{
Entity = e.Attribute("Name").Value,
Member = p.Attribute("Name").Value,
Type = p.Attribute("Type").Value,
Nullable = bool.Parse(p.Attribute("Nullable").Value),
};
Lets assume you're talking about the Contact Table in the assembly named YourAssembly in a Context called MyDataContext
Using Reflection against a Table
You can use reflection to get the properties like you would any type
var properties = from property in
Type.GetType("YourAssembly.Contact").GetProperties()
select property.Name
;
foreach (var property in properties)
Console.WriteLine(property);
As shaunmartin notes this will return all properties not just Column Mapped ones. It should also be noted that this will return Public properties only. You'd need to include a BindingFlags value for the bindingAttr Parameter of GetProperties to get non-public properties
Using the Meta Model
You can use the Meta Model System.Data.Linq.Mapping to get the fields ( I added IsPersistant to only get the Column Mapped properties)
AttributeMappingSource mappping = new System.Data.Linq.Mapping.AttributeMappingSource();
var model = mappping.GetModel(typeof (MyDataContext));
var table = model.GetTable(typeof (Contact));
var qFields= from fields in table.RowType.DataMembers
where fields.IsPersistent == true
select fields;
foreach (var field in qFields)
Console.WriteLine(field.Name);
Using Reflection from a query result
If on the other hand you wanted it from a query result you can still use reflection.
MyDataContextdc = new MyDataContext();
Table<Contact> contacts = dc.GetTable<Contact>();
var q = from c in contacts
select new
{
c.FirstName,
c.LastName
};
var columns = q.First();
var properties = (from property in columns.GetType().GetProperties()
select property.Name).ToList();
I stumbled upon this answer to solve my own problem and used Conrad Frix 's answer. The question specified VB.NET though and that is what I program in. Here are Conrad's answers in VB.NET (they may not be a perfect translation, but they work):
Example 1
Dim PropertyNames1 = From Prprt In Type.GetType("LocalDB.tlbMeter").GetProperties()
Select Prprt.Name
Example 2
Dim LocalDB2 As New LocalDBDataContext
Dim bsmappping As New System.Data.Linq.Mapping.AttributeMappingSource()
Dim bsmodel = bsmappping.GetModel(LocalDB2.GetType())
Dim bstable = bsmodel.GetTable(LocalDB.tblMeters.GetType())
Dim PropertyNames2 As IQueryable(Of String) = From fields In bstable.RowType.DataMembers
Where fields.IsPersistent = True
Select fields.Member.Name 'IsPersistant to only get the Column Mapped properties
Example 3
Dim LocalDB3 As New LocalDBDataContext
Dim qMeters = From mtr In LocalDB3.tblMeters
Select mtr
Dim FirstResult As tblMeter = qMeters.First()
Dim PropertyNames3 As List(Of String) = From FN In FirstResult.GetType().GetProperties()
Select FN.Name.ToList()
To display the results:
For Each FieldName In PropertyNames1
Console.WriteLine(FieldName)
Next
For Each FieldName In PropertyNames2
Console.WriteLine(FieldName)
Next
For Each FieldName In PropertyNames3
Console.WriteLine(FieldName)
Next
Please also read Conrad's answer for notes on each method!