I am trying to execute a raw query using c#.
Here is what I have done
var accounts = conn.Database.SqlQuery<IEnumerable<string>>("SELECT TOP 1 a.* FROM zipcodes_to_accounts AS c " +
"INNER JOIN accounts AS a ON a.id = c.account_id " +
"WHERE c.zip_code = #p0 "+
"ORDER BY a.completed_ll + a.completed_cp ASC", zipcode).ToArray();
Then I want to take the first record and convert it to json object.
if (accounts.Count() > 0)
{
return JsonConvert.SerializeObject( accounts.First() );
}
But the query is giving me an error
The result type 'System.Collections.Generic.IEnumerable`1[System.String]' may not be abstract and must include a default constructor.
The accounts table has some columns that are varchar, datetime, integers. How can I get this query to work?
UPDATED
Converting the IEnumerable to list like advised in the answer it working. but now the JsonConvert is returning an empty object. Here is my current code
//getAccount
public string GetAccount()
{
string zipcode = StringHelpers.StringOrNull(Request["zip_code"]);
if (zipcode != null)
{
var accounts = conn.Database.SqlQuery<List<string>>("SELECT TOP 1 a.* FROM zipcodes_to_accounts AS c " +
"INNER JOIN accounts AS a ON a.id = c.account_id "+
"WHERE c.zip_code = #p0 "+
"ORDER BY a.completed_ll + a.completed_cp ASC", zipcode).ToList();
var firstAccount = accounts.FirstOrDefault();
if (firstAccount != null)
{
return JsonConvert.SerializeObject(firstAccount);
}
}
return "{}";
}
When I debug my code Here is what I see
Not sure what ORM you're using, but the warning is telling you that IEnumerable cannot be constructed as it's an interface. Therefore the SqlQuery method can't know what return type you're expecting.
Try replacing the generic constraint with a concrete type:
var accounts = conn.Database.SqlQuery<string>("SELECT TOP 1 a.* FROM zipcodes_to_accounts AS c " +
"INNER JOIN accounts AS a ON a.id = c.account_id " +
"WHERE c.zip_code = #p0 "+
"ORDER BY a.completed_ll + a.completed_cp ASC", zipcode).ToArray();
You're asking for a IEnumerable<string> which is an interface. You need to pick a class that implements IEnumerable such as a List
Related
I am trying to create an update query in SQLKata that includes a 'FromRaw' statement. Below is a copy of my best attempt at what I am trying to accomplish. I have to use a FromRaw statement because I am linking 2 tables on an evaluation. Is there any way to accomplish this without having to resort to the Statement() function?
var query = db.Query(Table1)
.FromRaw(" Table1 INNER JOIN Table2 " +
" ON LEFT([Table1].[Company],5) = " +
" LEFT([Table2].[Company],5)" )
.Update(new { scrub = "match" });
Below is a copy of the error message:
System.InvalidOperationException: 'Invalid table expression'
This bit of code works just fine for me:
var compiler = new SqlServerCompiler();
//var Table1 = "Table1";
var query = new Query(null)
.FromRaw("Table1 INNER JOIN Table2 " +
"ON LEFT([Table1].[Company],5) = " +
"LEFT([Table2].[Company],5)")
.AsUpdate(new { scrub = "match" });
var rawSql = compiler.Compile(query).RawSql;
With rawSql value being:
UPDATE Table1 INNER JOIN Table2 ON LEFT([Table1].[Company],5) = LEFT([Table2].[Company],5) SET [scrub] = ?
The error message you're getting is only found in Compiler.cs, which is why I suggested that you check which compiler you're using.
var db = new SQLiteConnection(dbPath);
try
{
var results = db.Query<Xclass>("SELECT X.COL1, X.COL2, " +
" X.COL3, X.Col4, X.Col5, " +
" A.Col2, A.COL3, B.Col2, C.Col2 " +
"FROM left join Xam X " +
"left join TABLE1 A on X.COL1 = A.COL1 " +
"left join TABLE2 B on X.COL2 = B.COL1 " +
"left join TABLE3 C on X.COL3 = C.COL1 " +
"WHERE X.COL1 ='"+ somevalue +"'");
}
catch (Exception e)
{
// display message
}
XCLASS Contains all the getters and setters.
But it only pulls in the Xam table and not the A, B, or C table values.
I originally had the table name in the Class but took it out to see if that would help.
Any assistance is appreciated. I am trying to avoid linq but if is necessary I will try it.
The instance(s) of Xclass object is created from the results of your query via reflection.
The columns in query's result set are translated to properties of the class
and the setters of hese properties are used to assign their values.
Therefore you must supply some hints to SQlite so it will know which column corresponds to which property. This is done via as keyword.
So, if you want assign the value of A.COL2 column in the result to property named MyCol2Property inside Xclass, you must retrieve it in the query using the syntax
A.Col2 as MyCol2Property
I am trying to make a generic function to do a database call (see code below). I have put the function in a separate solution, so that i can use it in different projects.
the line:
var data = d.Database.SqlQuery<T> (sql).First();
gives me the error:
Invalid object name 'VM_MailData'
(VM_MailData is the type I add as generic type T)
public static void ProcessData<T>(string Group, int Id)
{
string ConnectionString = "SomeConnectionStringName";
string sql = "select top 1 * from " + (typeof (T).Name) + " where " + Group + "Id = " + Id + ";";
DbContext d = new DbContext(ConnectionString);
var data = d.Database.SqlQuery<T> (sql).First();
//Do some stuff with the data...
html = "some tekst...";
foreach (var sourceProperty in data.GetType().GetProperties())
{
html = html.Replace("{#" + sourceProperty.Name + "#}", sourceProperty.GetValue(data, new object[] { }) == null ? "" : sourceProperty.GetValue(data, new object[] { }).ToString());
//enter code here
}
}
You most probably need to call ProcessData<T>(string Group, int Id) with some base type of VM_MailData. I assume that VM stands for "view model" and you have something like
public class MailData
{
}
public class VM_MailData : MailData
{
}
Where MailData class is actually the one that has a corresponding table.
So instead of calling ProcessData<VM_MailData >("some group", 1) you need to call ProcessData<MailData>("some group", 1).
P.S. You really should use parameterized queries to avoid SQL Injection!
I can see where you're heading :) so...
You have to create a map (dictionary) that maps from Type to appropriate table name. You can built that using some kind of convention based on the name of the type or the tables.
Use those to get available tables and views in the dabatase
SELECT SCHEMA_NAME(schema_id) as SchemaName, name as Name FROM sys.tables
SELECT SCHEMA_NAME(schema_id) as SchemaName, name as Name FROM sys.views
You can use the following script to get the primary key column of the table.
DECLARE #origin_table_name AS VARCHAR(50)
SET #origin_table_name = 'Your_table_name_goes_here'
SELECT
s.name AS TABLE_SCHEMA
, t.name AS TABLE_NAME
, c.name AS COLUMN_NAME
, k.name AS CONSTRAINT_NAME
, ic.key_ordinal AS ORDINAL_POSITION
FROM
sys.key_constraints AS k
JOIN sys.tables AS t ON t.object_id = k.parent_object_id
JOIN sys.schemas AS s ON s.schema_id = t.schema_id
JOIN sys.index_columns AS ic ON ic.object_id = t.object_id
AND ic.index_id = k.unique_index_id
JOIN sys.columns AS c ON c.object_id = t.object_id
AND c.column_id = ic.column_id
WHERE
k.type = 'PK'
AND t.name = #origin_table_name
Good luck
I'm following Mikes post on the IN Clause on http://www.mikesdotnetting.com/article/156/webmatrix-database-helpers-for-in-clauses but I'm having trouble adding additional params. As per his post, I started with some checkboxes for the categories and worked fine but I added some other checkboxes for the brands but it's not working. I'm not sure how to pass additional params to the in clause.
The idea of what I want to accomplish is to have a side bar with different product filters (categories, brands, age, price, etc) and as the user clicks it will update the results. Can someone please help me on this one?
This is the code i'm working with but this gives errors:
// for the categories
var cTemp = Request["categoryId"].Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
var cParms = cTemp.Select((s, i) => "#" + i.ToString()).ToArray();
var cIn = string.Join(",", cParms);
// for the brands
var bTemp = Request["brandId"].Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
var bParms = bTemp.Select((s, i) => "#" + i.ToString()).ToArray();
var bIn = string.Join(",", bParms);
var sql = "SELECT DISTINCT P.ProductID, J.CategoryID, J.BrandID, P.ProductName, P.Price, " +
"FROM Products P " +
"JOIN Junction J ON J.ProductID = P.ProductID " +
"WHERE J.CategoryID IN ({0}) OR J.BrandID IN ({1})";
var products = db.Query(String.Format(sql, cIn, bIn), cTemp, bTemp);
Inspect the value of String.Format(sql, cIn, bIn) - make it a separate string variable. You will see that you have duplicate parameter names in this SQL expression: #0, #1, etc.
When calling db.Query, do:
db.Query(<final sql statement>, allTemp)
where allTemp is concatenation of cIn and bIn.
Item 2 is the cause of the error that you see.
For the error you mentioned in the comment, try removing parameters from db.Query method.you are passing string array to sql parameters,which is not correct. Your method call should be this.
var products = db.Query(String.Format(sql, cIn, bIn));
I think there is also error in your WHERE clause handling. Try something like this..
var sql = "SELECT DISTINCT P.ProductID, J.CategoryID, J.BrandID, P.ProductName, P.Price, " +
"FROM Products P " +
"JOIN Junction J ON J.ProductID = P.ProductID ";
var whereClause = ""
if(!string.IsNullOrEmpty(cIn)||!string.IsNullOrEmpty(bIn))
{
whereClause = "WHERE";
if(!string.IsNullOrEmpty(cIn))
{
whereClause+=" J.CategoryID IN ({0}) ";
if(!string.IsNullOrEmpty(bIn))
whereClause+=" OR ";
}
if(!string.IsNullOrEmpty(bIn))
{
whereClause+=" J.BrandID IN ({1}) ";
}
}
sql = sql+whereClause;
enter code hereIn my SQL Server database I have my address information for the subNumber (e.g. Unit 802) and the streetNumber (e.g. 242 Elizabeth Street) stored separately.
I need to display these as one (i.e. 802/242 Elizabeth Street) if the subNumber contains a value, otherwise just return the streetNumber if it does not.
I've been working toward a solution using IF ELSE and a foreach loop after accessing the data through LINQ - but I'm stuck after the point where I have completed the loop. I would also be happy to do this with a SELECT Stored Procedure in SQL - open to suggestions!
DataClassesDataContext dc = new DataClassesDataContext();
var recent = from p in dc.Properties
orderby p.modtime descending
where p.status == "Current"
select new
{
rsub = (p.subNumber).ToString(),
rnumber = (p.streetNumber).ToString(),
rstreet = p.street,
rsuburb = p.suburb,
rurl = p.propertyURL,
};
foreach (var home in recent)
{
if (string.IsNullOrEmpty(home.rsub))
{
string rnum = home.rnumber;
}
else
{
string rnum = home.rsub + "/" + home.rnumber;
}
}
recentrepeater.DataSource = recent;
recentrepeater.DataBind();
Yahia gave the best option in c# - this is the SQL solution I have finally ended up with:
ALTER PROCEDURE GetPropertyShort
AS
SELECT TOP 5 ISNULL(convert(varchar(5), subNumber) + '/' + convert(varchar(5), streetNumber), convert(varchar(5), streetNumber)) as Number, street, suburb, propertyURL, modtime
FROM Property
ORDER BY modtime DESC
try
var recent = from p in dc.Properties
orderby p.modtime descending
where p.status == "Current"
select new
{
rsub = (p.subNumber).ToString(),
rnumber = (p.streetNumber).ToString(),
rnum = string.IsNullOrEmpty((p.subNumber).ToString()) ? (p.streetNumber).ToString() : (p.subNumber).ToString() + "/" + (p.streetNumber).ToString(),
rstreet = p.street,
rsuburb = p.suburb,
rurl = p.propertyURL,
};
Just a ternary conditional aka ?: operator in the "select" should do:
select new
{
house = p.subNumber != null
? p.subNumber + "/" + p.streetNumber
: p.streetNumber;
...
};
This makes the assumption street number is always there (or it might result in "xxx/" or null). It also assumes that sub is null (not just empty) if truly not present.
If it starts to get "too complicated", consider the following (which has slightly different rules than above, those are left to be figured out):
select new
{
house = PrettyHouseNumber(p.subNumber, p.streetNumber),
...
};
string PrettyHouseNumber(string sub, string street) {
// ?: could also be used here as well, but since invoking the method
// can be used as an expression itself, breaking it up like this also
// allows the use of other constructs
if (!string.IsNullOrEmpty(sub)) {
return sub + "/" + street;
} else {
return "" + street; // NULL will go to "", if it can even ever come up
}
}
Which should show how any expression, including a method call, can be used there -- pass it some data and get some data back :) While there are limits with expression trees and which ones can be efficiently turned into SQL, since this is just processing data already returned then there is nothing to worry about here.
Happy coding.
On the table level you could create a computed column; these are not stored - the value is 'created' when the column is queried.
CREATE TABLE [Customer]
(
[subNumber] NVARCHAR(256),
[streetNumber] NVARCHAR(256),
[fullAddress] AS (CASE
WHEN [subNumber] IS NULL THEN [streetNumber]
ELSE [subNumber] + N' ' + [streetNumber]
END)
);
GO
Or you can add it the table:
ALTER TABLE [Customer]
ADD COLUMN [fullAddress]
AS (CASE
WHEN [subNumber] IS NULL THEN streetNumber
ELSE [subNumber] + N' ' + streetNumber
END);
GO
Now the value will be directly-accessible from your EF model.