I want query all the existing tables whose name begin with specific string in database using oledb GetSchema method.
In other words I am looking for equivalent of the following sql query:
SELECT * FROM information_schema.tables WHERE table_name LIKE 'customer%'
Something like:
String[] tableRestrictions = new String[4];
tableRestrictions[2] = "%customer";
DataTable customerTables = conn.GetSchema("Tables", tableRestrictions );
In this case the table name I want to query from is Dynamic. Therefore I needed to get the whole table name first.
It seems there is not efficient way to do that but using an iteration.
I came to this conclusion that using Linq provides the neatest solution(Thanks to Tim's answer to a similar case):
// Get the tables using GetSchema:
dtbTables = dbConnection.GetSchema("tables");
// use linq to get the table whose name matches the criteria:
DataRow recSpecificTable = dbConnection.GetSchema("Tables").AsEnumerable()
.Where(r => r.Field<string>("TABLE_NAME")
.StartsWith("customer")).FirstOrDefault();
// Now the table name I am looking for:
tableName = Convert.ToString(recSpecificTable["TABLE_NAME"]).Trim();
Related
I have a SQLite database contains several tables which some of them (not all) have a specific column called 'attachment'. I wonder if there is a query that get values of the 'attachment' column from all the tables which have this column. I can get all tables' name from the database, and then, query all tables individually. But I think there must be a single query to do this.
You can use SQLite code to get the sql SELECT statement as a string and execute it to get all the values of the column attachment in all tables of the database:
SELECT GROUP_CONCAT('SELECT ' || pti.name || ' FROM ' || sm.name, ' UNION ALL ') sql
FROM sqlite_master sm CROSS JOIN pragma_table_info(sm.name) pti
WHERE sm.type = 'table' AND pti.name = 'attachment';
The above query returns a resultset with only 1 row and 1 column aliased as sql with a value of a string like this:
SELECT attachment FROM table1
UNION ALL
SELECT attachment FROM table2
UNION ALL
SELECT attachment FROM table4
You can change UNION ALL to UNION inside the function GROUP_CONCAT(), depending on your requirement.
See a simplified demo.
You can get the values of every attachment field in every table that has this field defined using the GetSchema method on the connection to find all the relevant tables then you can use the sql stament UNION to extract in a single command all the attachments values.
This should be the code using only standard ADO.NET commands and methods:
using(SQLiteConnection cnn = new SQLiteConnection(#"Data Source=E:\\temp\\mydb.db;Version=3"))
{
cnn.Open();
// We want all columns with the name as "attachment"
DataTable dt = cnn.GetSchema("COLUMNS", new string[] {null, null, null, "attachment"});
// Now we prepare the single commands that extract the attachments value
// from every row returned by the previous query.
// The TABLE_NAME field contains the name of the relevant table
var s = dt.AsEnumerable().Select(x => $"SELECT attachment FROM [{x.Field<string>("TABLE_NAME")}]");
// We join together the single commands separating them with the UNION statement
string command = string.Join(" UNION ", s);
// Finally we can construct and execute a command loading a datatable
// with all the attachements values from every table.
SQLiteCommand cmd = new SQLiteCommand(command, cnn);
dt = new DataTable();
dt.Load(cmd.ExecuteReader());
// Here you can work on the single field in the _dt_ table
....
}
Note, UNION will extract a distinct value for each attachment. This means that if you have two attachments with the same name, it will be listed only one time. If you want to keep everything then change UNION to UNION ALL (with spaces before and after the statement)
List<Order> results = new List<Order>();
db.Cmd = db.Conn.CreateCommand();
db.Cmd.CommandText = "SELECT * FROM Order";
db.Rdr = db.Cmd.ExecuteReader();
while (db.Rdr.Read())
{
results.Add(getOrderFromReader(db.Rdr));
}
db.Rdr.Close();
return results;
I get this error when this code runs
System.Data.SqlClient.SqlException: 'Incorrect syntax near the keyword 'Order'.'
The result is a list of Order objects. The name of the table is Order exactly. The method getOrderFromReader just takes a row of data from the order table and in puts it into a new order object. I have used this format of code to extract data from all of the tables in the database and the rest works fine but its just the Order table that I get this error for, I don't know if this is because of other settings in the database.
You will need to put the name of the table in square brackets in order for it to work.
List<Order> results = new List<Order>();
db.Cmd = db.Conn.CreateCommand();
db.Cmd.CommandText = "SELECT * FROM [Order]";
db.Rdr = db.Cmd.ExecuteReader();
while (db.Rdr.Read())
{
results.Add(getOrderFromReader(db.Rdr));
}
db.Rdr.Close();
return results;
Order is a SQL reserved word, so you might think about renaming that table, if you can.
Order is a keyword in SQL used for Ordering/sorting of the resultset.
Here the complier is getting confused with the keyword and your table name.
Solutions :
Rename your table name
Enclose your table name in brackets. [Order]. ie,
Select * From [Order]
I'm using entity framework, and I need to get a list of entities only by passing the name of the entity.
Example:
string tableName = "PRODUCT";
List<tableName> myList = (from prod in dbContext.tableName
select prod).ToList();
What I can't get to do, is that, using the table name (string) to make a EF query (or LINQ).
I'm trying to get this to work by using Reflection or EntityDataModel, but I just can't.
Have you tried something like this (source):
var table = context.ExecuteStoreQuery<ResultTableTemplate>("SELECT ... FROM " + tableName);
Up to now (with NHibernate) I've used entity mapping and not really got involved with creating raw sql queries - but somethings come up where I need to do exactly that.
The problem I have is I want to automatically map the columns aliases of my query to a Dto object.
This works, but i have to specify the column alias' in the order of the query.
SQL
string sql = "select mycol1 as ColumnOne from mytable";
NHibernate Query
var query = session.CreateSQLQuery(sql)
.AddScalar("ColumnOne", NHibernateUtil.Int32)
.SetResultTransformer(
NHibernate.Transform.Transformers.AliasToBean<MyDtoObject>()
);
MyDtoObject
public class MyDtoObject
{
public int ColumnOne {get;set;}
}
But is there a way to making NHibernate automate the mapping between the columns in the query and the Dto without creating a mapping class?
I've seen some examples of using aliases in the query e.g.
string sql = "select mycol1 as {ColumnOne} as ColumnOne from mytable"; /// ???
But cannot get this to work as the alias {ColumnOne} appear not to be replaced before being sent to the db as a sql statement.
Any idea?
TIA
Sam
Maybe System.Linq.Dymanic will help:
use System.Linq.Dynamic;
string ColumnAlisName = "ColumnOne";
var query = mytable.Select(String.Format("new (mycol1 as {0})",ColumnAlisName));
If I have the name of a database table like this:
string tableName = "Addresses";
string tableName = "Customers";
How can I construct a dynamic LINQ statement like this:
var items = from o in db.{tableName}
select o;
foreach (var item in items)
{
sb.Append(item.Id + Environment.NewLine);
}
I know I could do something like this:
IEnumerable<Customer> results = db.ExecuteQuery<Customer>
("SELECT contactname FROM customers WHERE city = {0}",
"London");
But in this instance I don't want strongly typed objects as my result, I just want a recordset to pick apart.
Answer:
Thanks Shalkalpesh, I took your advice and solved this by just avoiding LINQ altogether:
SqlConnection conn = new SqlConnection();
conn.ConnectionString = ConfigurationManager.ConnectionStrings["main"].ToString();
conn.Open();
string sql = "SELECT * FROM " + tableName;
SqlDataAdapter da = new SqlDataAdapter(sql, conn);
DataTable dtResult = new DataTable();
da.Fill(dtResult);
foreach (DataRow drRow in dtResult.Rows)
{
Console.WriteLine(drRow["Id"].ToString());
}
da.Dispose();
conn.Close();
conn.Dispose();
If you want the recordset, you can access the Connection property of the DataContext class (db variable in your context) and use it to execute regular query and get the result in either of DataTable or DataReader.
You can use the Dynamic Linq Query library (or D-Linq for short).
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
Sorry - I'm away from a dev machine at the moment, but would this help?
It seems to suggest you should use DynamicQuery ...
Another way - as was mentioned by
several commenters in my previous post
- is to use DynamicQuery. DynamicQuery is one of the samples installed with
the 101 LINQ samples and you can find
it by clicking on Help | Samples in
Visual Studio. If you drill into the
sample folders there's a DynamicQuery
sample project, which basically
consists of a class that provides
string based lambda expression
parsing.
The class DynamicQuery class is self
contained and you can simply add it to
your project. It provides additional
extension methods that let you use
string expressions for various of the
query methods including the .Where()
method (but unfortunately for the
above example not the .Single()
method). So with Dynamic Query the
above .Load() method can also be
written as follows:
There's an actual code example on the post, too...
LINQ to SQL is meant to be strongly typed so I don't think you can use LINQ to SQL to use dynamic table names unless you use ExecuteQuery
Thanks
I don't think Dynamic Linq is the solution here.
As far as I know, there is no solution to your problem.
Even with dynamic linq, the compiler would need to somehow figure out what table the string refers to at compile time to allow strong typing of its members.
For instance, let's say you have two tables:
Product {Id, Name, Value}
Customer {Id, Firstname, Surname, Address, Email, ...}
And you use Linq-to-SQL as your ORM:
var items = from p in MagicTableResolver("Product")
where p.Firstname // <-- How could intellisense allow this?
select p;
var items = from c in MagicTableResolver("Customer")
where c.Name // <-- It can't, it cannot be strongly typed
select c;
Building off of this and this, here's how to run some some LINQ commands on a string tablename. I haven't figured out how to get the query syntax working (like "FROM" and "SELECT"), but you can still get and insert rows.
Type tableType = Assembly.GetExecutingAssembly().GetType("NameSpace.TableName");
ITable itable = dbcontext.GetTable(tableType);
//prints contents of the table
foreach (object y in itable) {
string value = (string)y.GetType().GetProperty("ColumnName").GetValue(y, null);
Console.WriteLine(value);
}
//inserting into a table
dynamic tableClass = Activator.CreateInstance(tableType);
//Alternative to using tableType
dynamic tableClass = Activator.CreateInstance(null, "NameSpace.TableName").Unwrap();
tableClass.Word = userParameter;
itable.InsertOnSubmit(tableClass);
dbcontext.SubmitChanges();
//sql equivalent
dbcontext.ExecuteCommand("INSERT INTO [TableName]([ColumnName]) VALUES ({0})", userParameter);