Im working with Entity Framework version 6.1.3 and I want to execute a SQL-query
which gathers information from multiple tables like this:
var result = context.Database.SqlQuery<SomeType>("SELECT SUM(d.PurchaseValue) AS 'Total', div.Name, l.Name " +
"FROM Device AS d " +
"RIGHT JOIN Location AS l " +
"ON d.LOCATION_ID = l.ID " +
"RIGHT JOIN Division AS div " +
"ON d.DIVISION_ID = div.ID " +
"GROUP BY div.Name, l.Name " +
"ORDER BY l.Name");
My question is, what should be the the type in SqlQuery<>? Or what is the proper way to execute a query like this and get a result out of it?
Here SomeType can be any type that has properties which match the names of the columns returned from the query.
For example, your query returns columns:
Total | Name
Therefore, your return type (class) can be similar to below...
public class SomeType
{
public string Name { get; set; }
public decimal Total { get; set; }
}
Your query will be
var result = context.Database.SqlQuery<List<SomeType>>(...);
Have you seen checked the Data Development Center for ways to do this?
Note 'Entity Framework allows you to query using LINQ with your entity classes. However, there may be times that you want to run queries using raw SQL directly against the database.'
So if you can, use LINQ. Check here and here to start.
Related
I have the following function that I am trying to run that joins a product table and a productcategory table and return the results. The debugger, when exception is thrown, displays the query string and I have tried running the query string in my test mysql database and it works.
The CategorizedProduct is a model. I have checked and made sure that all the fields in the select list match the fields in the model.
I cannot find where the error is.
public static List<CategorizedProduct> GetAllCategorizedProducts(string category)
{
using (var conn = Sql.GetConnection())
{
string queryString = "select ProductID,ProductName,ProductType,ProductCategory,CategoryName,Unit,PricePerUnit,IsAvailable,NumberOfUnits,RemainingUnits,WeightPerUnit" +
" from product inner join productcategory where product.ProductCategory = productcategory.CategoryID and CategoryName = \'" + category + "\' order by ProductType;";
return conn.Query<CategorizedProduct>(queryString).ToList();
}
}
Try this version instead:
select ProductID, ProductName, ProductType, ProductCategory,
CategoryName, Unit, PricePerUnit, IsAvailable, NumberOfUnits,
RemainingUnits, WeightPerUnit
from product inner join
productcategory
on product.ProductCategory = productcategory.CategoryID
where CategoryName = \'" + category + "\'
order by ProductType;
I do think that the on is optional in MySQL after join, but this might fix your problem. The on is required by any other database (and I think if you have certain ANSI settings on in MySQL).
I have three tables, one holds a list of available products with relevant details such as product price, the other holds orders and the last holds specific order details including the items purchased in an order.
I am trying to create a query to calculate the total price of an order by linking the two of the tables with an inner join and then updating the order table with the value. The code I have written contains syntax errors, being a novice I have probably made an obvious mistake but any help would be appreciated.
"SELECT Sum(ProductTable.prodPrice) AS Total, OrderDetailTable.orderID " +
"FROM ProductTable INNER JOIN OrderDetailTable " +
"ON ProductTable.prodID = OrderDetailTable.prodID " +
"GROUP BY OrderDetailTable.orderID " +
"HAVING OrderDetailTable.orderID = ? " +
"UPDATE OrderTable " +
"SET " +
"totalPrice = Total " +
"WHERE OrderTable.orderID = ? ";
I am using Access.
I also forgot to mention that the ? is represented using a Dataview parameter
pc.Add(new Parameter("?", TypeCode.Int32, basketId.ToString()));
EDIT: Using PaqoGomez's suggestion to declare Total as a value I now get the error : Syntax error (missing operator) in query expression '0WHERE OrderTable.orderID = ?'.
Comment made before OP described this as MS Access:
Haven't tried this but you had the Select and update the wrong way round. This should be quite close. Its been a while for me but you may need to change the FROM clause to reference the table you are updating and INNER JOIN the sub-select instead of the WHERE clause.
"UPDATE OrderTable " +
"SET totalPrice = Sum(ProductTable.prodPrice)" +
"FROM (" +
"SELECT OrderDetailTable.orderID, Sum(ProductTable.prodPrice)" +
"FROM ProductTable INNER JOIN OrderDetailTable " +
"ON ProductTable.prodID = OrderDetailTable.prodID " +
"GROUP BY OrderDetailTable.orderID " +
") x" +
"WHERE x.orderID = OrderTable.OrderId"
UPDATE :
Based on OPs update regarding MS Access you can do an update with a sub-query, but I think it depends on the version of MS Access you are using and how you do it. Posts below seem to indicate it's quite problematic:
SQL Subqueries (Microsoft Access SQL)
How do I perform update query with subquery in Access?
Can It Be Done - Access 2007 SQL Update Query Using a Subquery?
By declaring a variable you can save the total value so that you can use it in the later update.
declare #Total int;
SELECT #Total = Sum(ProductTable.prodPrice)
//...
"SET " +
"totalPrice = #Total "
You dont mention which database platform you are using, I'm assuming MSSQL, other platforms would require a slightly different syntax.
You might also be interested to know that if you use the # symbol you can have a multiline string. This would allow you to avoid the concatenation that you are doing. eg.
var sql = #"some
sql
string"
I feel like this is something simple and I'm just missing it...
Need to do a quick and dirty text search on FirstName and LastName columns together from a model like this:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Sample data:
FirstName LastName
-------------------------------
John Appleseed
John Anderson
Chris Cringle
George Washington
Backend is SQL Server, using LINQ to Entities and Entity Framework 6, I need to do a lookup on the full name, but something like this won't work:
var results = from p in db.Persons
where (p.FirstName + ' ' + p.LastName).Contains(keyword)
select p;
LINQ doesn't like that. This is for an autocomplete method; I want it to be able to find the results for "john a" if somebody types that -- it would be the first two rows from the sample data.
How can I do it?
EF can only concat strings; it cannot concat characters. Were it LINQ to Objects the char would be converted to a string without any problems, but EF just isn't robust enough to do that. The fix is trivial enough though; use a literal string, not a literal character, for the space:
var results = from p in db.Persons
where (p.FirstName + " " + p.LastName).Contains(keyword)
select p;
So I'm retrieving data from the database using odbc. One of my fields, which was causing the problem, is AutoNumber. In my query when I use, '" convert.toint64(empid)"', I get an error of data type missmatch. But when I used parameter, it worked perfectly. Can someone tell me what is the difference. As far as I know, AutoNumber is a long integer and long int is 64, right?
here are both of my queries:
string cmdText = "SELECT p.projID, p.projName, a.wageperday " +
"FROM ((projects p INNER JOIN assigns a ON p.projID = a.projname) " +
"INNER JOIN empos e ON a.employeeID= e.ID) " +
"WHERE a.employeeID = ?";
OdbcCommand assignslist = new OdbcCommand(cmdText, _connection);
assignslist.Parameters.AddWithValue("#empID", empid);
OdbcDataReader readassigns = assignslist.ExecuteReader();
GridView1.DataSource = readassigns;
GridView1.DataBind();
(this one works fine)
string cmdText = "SELECT p.projID, p.projName, a.wageperday " +
"FROM ((projects p INNER JOIN assigns a ON p.projID = a.projname) " +
"INNER JOIN empos e ON a.employeeID= e.ID) " +
"WHERE a.employeeID = '" + convert.toint64( empid ) + "';
OdbcCommand assignslist = new OdbcCommand(cmdText, _connection);
OdbcDataReader readassigns = assignslist.ExecuteReader();
GridView1.DataSource = readassigns;
GridView1.DataBind();
for this one, i get an error even if I removed the conversion, I get an error.
One more question, I don't understand INNER JOIN perfectly and the above code was from a user here who helped me. I don't understand why did he use "FROM ((projects p INNER JOIN assigns a ON p.projID = a.projname) " +
"INNER JOIN empos e ON a.employeeID= e.ID)"
two brackets -- I mean a bracket inside a bracket. And if I wanna join a 4th or 5th table do I have to put it inside a bracket aside from the main bracket? An example would be much appreciated!
If a.employeeID is a number then your problem are the quotes and the concatenation of a number to a string.
"WHERE a.employeeID = " + convert.toint64(empid).ToString()
but this make no sense because you have a string to build so, you could simply write
"WHERE a.employeeID = " + empid.ToString();
however use always the parameterized query. That is the correct way to go.
A parameterized query allows the Framework code to pass the parameters with the correct format and you don't have to worry about quoting values, format of dates and decimal separators. (And last but not least, you avoid any possibilities of Sql Injection)
For the second part of your question, JOIN is used to put togheter data from two tables, when you have more than one JOIN the parenthesys help to understand how the grouping from the tables are perfomed. First the data from projects and assigns are grouped together following the rules of the INNER JOIN then the resulting set of data is joined with the data from the employee table following the rules of the second join.
In your second query, instead of using convert.toint64( empid ) try using empid.ToString():
"WHERE a.employeeID = " + empid.ToString();
The error you were receiving was due to the fact that you were trying to concatenate a string with an integer.
With regards to the INNER JOINs you are using, the use of the brackets is dependant upon the database you are using. In most cases, you will not need the brackets at all and they can be removed without any issue, so you could rewrite the query to:
string cmdText = "SELECT p.projID, p.projName, a.wageperday " +
"FROM projects p " +
"INNER JOIN assigns a ON p.projID = a.projname " +
"INNER JOIN empos e ON a.employeeID = e.ID " +
"WHERE a.employeeID = " empid.ToString();
You're trying to add a string and an integer, which isn't allowed automatically. You'd have to convert the number to a string first, like this:
"WHERE a.employeeID = '" + empid.ToString() + "';
But, using parameters is the better way for other reasons (best habit to be in, to avoid SQL-injection attacks, etc.).
Is it possible to turn this into an entity framework query that will only query the database once?
select max(TableADate) latestTableADate, max(TableBDate) latestTableBDate
from
(
select max(a.ModifiedDate) TableADate, null TableBDate
from TableA a
union all
select null, max(b.ModifiedDate)
from TableB b
) data
The intent is to get the latest ModifiedDate from multiple tables with one sql statement so Entity Framework is not doing multiple trips to the database to get the data.
I need to know when the last time that one of the tables was updated.
Update:
I ended using DbContext.Database.SqlQuery doing the following:
var output = db.Database.SqlQuery<DateTime>
("select data from (" +
"select 1 orderBy, max(ModifiedDate) data from TableA" +
"union all " +
"select 2, max(ModifiedDate) from TableB " +
") temp order by orderby").ToList();
data.TableADate = output[0];
data.TableBDate = output[1];
You can execute a query similar to the one you've listed using the DbContext.Database.SqlQuery method. You'd need to change it to return the dates in some sort of order or use out parameters.