How to use SQL Raw query in ASP .Net MVC web api - sql

My Connection String:
<add name="addConnection" connectionString="Data Source=(LocalDb)\v11.0;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\FLWorkDB.mdf" providerName="System.Data.SqlClient" />
<add name="FLWorkDBEntities" connectionString="metadata=res://*/MyEdmx.csdl|res://*/MyEdmx.ssdl|res://*/MyEdmx.msl;provider=System.Data.SqlClient;provider connection string="data source=(LocalDB)\v11.0;attachdbfilename=|DataDirectory|\FLWorkDB.mdf;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
My Web API:
[HttpGet]
[Route("api/JobApi/BrowseJobs/")]
public object BrowseJobs()
{
using (var ctx = new FLWorkDBEntities())
{
//Get student name of string type
object studentName = ctx.Database.SqlQuery<string>(#"Select j.JobID,j.JobDetails,j.JobTitle, j.Deadline ,j.Budget,j.Category, emp.FirstName,emp.LastName,Skills = Stuff((Select ',' +SkillName From Skill Where charindex(concat(',',SkillID,','),','+j.ReqSkill+',')>0 For XML Path ('')),1,1,'')
From Job j
join Employeer emp on j.EmployeerID = emp.EmployeerID
WHERE NOT EXISTS
(SELECT *
FROM ClosedJob c
WHERE c.JobID = j.JobID) AND
NOT EXISTS
(SELECT *
FROM AppliedJob apj
join JobOffer jo on apj.AppliedJobID =jo.AppliedJobID
join Contract con on jo.OfferID =con.OfferID
WHERE con.CompletedDate != Null)").ToList();
}
return stu;
}
Now i am doing all with LINQ. But i want to avoid LINQ and add direct sql query.
RAW Sql: "Select * from A where A.ID =2"(with join)
I want to add the RAW SQL Query in my web api that returns list in json.
Can i add sql query without entity framework, i mean .edmx file?
Edited==============
Tried this:
var results = db.Database.SqlQuery<FLWorkDBEntities>(#"Select j.JobID,j.JobDetails,j.JobTitle, j.Deadline ,j.Budget,j.Category, emp.FirstName,emp.LastName,Skills = Stuff((Select ',' +SkillName
From Skill
Where charindex(concat(',',SkillID,','),','+j.ReqSkill+',')>0
For XML Path ('')),1,1,'')
From Job j
join Employeer emp on j.EmployeerID = emp.EmployeerID
WHERE NOT EXISTS
(SELECT *
FROM ClosedJob c
WHERE c.JobID = j.JobID) AND
NOT EXISTS
(SELECT *
FROM AppliedJob apj
join JobOffer jo on apj.AppliedJobID =jo.AppliedJobID
join Contract con on jo.OfferID =con.OfferID
WHERE con.CompletedDate != Null)").ToList<FLWorkDBEntities>();
return JsonConvert.SerializeObject(results);
But returns:
Self referencing loop detected with type 'System.Data.Entity.DynamicProxie
================Solved====================
I made a stored procedure (BrowseJobs) then attached it with the following code
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["addConnection"].ConnectionString);
SqlCommand com = new SqlCommand("BrowseJobs", con);
com.CommandType = CommandType.StoredProcedure;
SqlDataAdapter da = new SqlDataAdapter(com);
DataSet ds = new DataSet();
da.Fill(ds);
return ds.Tables[0];

Yes. You can go through this link http://www.entityframeworktutorial.net/EntityFramework4.3/raw-sql-query-in-entity-framework.aspx
E.g.;
using (var context = new SqlDbContext())
{
//Get command for non entity types
string studentName = context.Database.SqlQuery<string>(#"SELECT StudentName FROM Student WHERE StudentID = 1").FirstOrDefault<string>();
//Get command for entity types. SQL columns returned by SQL query should match the property of the entity type
var students = context.Students.SqlQuery(#"SELECT * FROM Student").ToList<Student>();
//Update command
int noOfRowsUpdated = context.Database.ExecuteSqlCommand(#"UPDATE Student SET StudentName = 'New Name' WHERE StudentID = 1");
//Insert command
int noOfRowsInserted = context.Database.ExecuteSqlCommand(#"INSERT INTO Student(StudentName) VALUES('New Student')");
//Delete command
int noOfRowsDeleted = context.Database.ExecuteSqlCommand(#"DELETE FROM Student WHERE StudentID = 1");
}
You can return the list in JSON format using Newtonsoft.Json. Just follow these steps:
PM> Install-Package Newtonsoft.Json
using Newtonsoft.Json;
var jsonResult = JsonConvert.SerializeObject(students);

You can do this in entity framework.
The documentation link : https://msdn.microsoft.com/en-us/library/jj592907(v=vs.113).aspx
example link : http://www.entityframeworktutorial.net/EntityFramework4.3/raw-sql-query-in-entity-framework.aspx
To, do it without edmx then use old ado.net.

Related

Table Cloud Storage gives exception The remote server returned an error: (404) Not Found.

I am having an issue with Querying Azure Table Storage-
public List<SubCategoryModel> GetSubCategories()
{
string connStr = ConfigurationManager.ConnectionStrings["ConnString"].ConnectionString;
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connStr);
CloudTableClient client = storageAccount.CreateCloudTableClient();
CloudTable table = client.GetTableReference("SubCategories");
List<SubCategoryModel> subCategoryModels = new List<SubCategoryModel>();
TableQuery<SubCategoryEntity> subCategoriesQuery = table.CreateQuery<SubCategoryEntity>();
var query = (from subCategory in subCategoriesQuery
select subCategory).AsTableQuery();
var subCategories = query.Execute();
foreach (SubCategoryEntity entity in subCategories)
{
SubCategoryModel subCategoryModel = new SubCategoryModel();
subCategoryModel.CATEGORYID = entity.CategoryId;
subCategoryModel.DESCRIPTION = entity.Description;
subCategoryModel.SUBCATEGORY = entity.SubCategoryName;
subCategoryModel.SUBCATEGORYID = entity.SubCategoryId;
subCategoryModels.Add(subCategoryModel);
}
return subCategoryModels;
}
web.config:
<add name="ConnString" connectionString="UseDevelopmentStorage=true;DevelopmentStorageProxyUri=http://127.0.0.1"></add>
Oops My Bad...I was getting the error because my Table Name was SubCategory.
And I had SubCategories Written in code.
My Bad. Fixed it. Yes!!

MS SQL Query in C# - poor performance

I calculate outstanding customers balance in C# Winforms. The code below works, but it's slow. Is there any way to improve its performance?
public DataTable GetOutStandingCustomers()
{
decimal Tot = 0;
DataTable table = new DataTable();
SqlConnection con = null;
try
{
table.Columns.Add("Code", typeof(Int32));
table.Columns.Add("Name", typeof(string));
table.Columns.Add("City", typeof(string));
table.Columns.Add("Tot", typeof(decimal));
string constr = ConfigHelper.GetConnectionString();
string query = "SELECT Code, Name,City FROM Chart WHERE LEFT(CODE,3)='401' AND Code > 401001 ";
string query0 = " SELECT(SELECT ISNULL( SUM(SalSum.Grand),'0' ) FROM SalSum WHERE SalSum.Code = #Code ) +( SELECT ISNULL(SUM(Journals.Amount),'0' ) FROM Journals WHERE Journals.DrCode = #Code ) -( SELECT ISNULL(SUM(RSalSum.Grand),'0' ) FROM RSalSum WHERE RSalSum.Code = #Code ) -( SELECT ISNULL(SUM(Journals.Amount),'0' ) FROM Journals WHERE Journals.CrCode = #Code )+(SELECT ISNULL(SUM(Chart.Debit),'0' ) FROM Chart WHERE Chart.Code = #Code) - (SELECT ISNULL(SUM(Chart.Credit), '0') FROM Chart WHERE Chart.Code = #Code)";
Person per = new Person();
con = new SqlConnection(constr);
SqlCommand com = new SqlCommand(query, con);
SqlCommand com0 = new SqlCommand(query0, con);
con.Open();
SqlDataReader r = com.ExecuteReader();
if (r.HasRows)
{
while (r.Read())
{
per.Name = Convert.ToString(r["Name"]);
per.City = Convert.ToString(r["City"]);
per.Code = Convert.ToString(r["Code"]);
com0.Parameters.Clear();
com0.Parameters.Add("#Code", SqlDbType.Int).Value = per.Code;
Tot = Convert.ToDecimal(com0.ExecuteScalar());
if (Tot != 0)
{
table.Rows.Add(per.Code, per.Name, per.City, Tot);
}
}
}
r.Close();
con.Close();
return table;
}
catch (Exception)
{
throw new Exception();
}
}
The performance problem is due to you retrieve all data from the server and filter data in the client using the complex computed expression that sum from seven tables:
if (Tot != 0)
{
table.Rows.Add(per.Code, per.Name, per.City, Tot);
}
This represent overhead over network plus you manually add the result to the datatable row by row.
The provided solution do filter in the server based on the computed expression using the CROSS APPLY
and auto create the datatable directly from the DataReader.
The benefit of CROSS APPLY is all columns are feasible to the main sql query, so you can filter on ToT column, filtering is done in the server (not the client).
public void SelctChart()
{
string sql2 = #"
select c.Code, c.Name,c.City ,oo.T
from chart c
cross apply
( select c.code,
(
(select ISNULL( SUM(SalSum.Grand),0 ) FROM SalSum WHERE SalSum.Code = c.code )
+( select ISNULL(SUM(j.Amount),0 ) FROM [dbo].[Jornals] j WHERE j.DrCode = c.code)
-( SELECT ISNULL(SUM(RSalSum.Grand),'0' ) FROM RSalSum WHERE RSalSum.Code = c.Code )
-( SELECT ISNULL(SUM(j.Amount),0 ) FROM [dbo].[Jornals] j WHERE j.CrCode = c.code )
+(SELECT ISNULL(SUM( c0.Debit),0 ) FROM [dbo].Chart c0 WHERE c0.Code = c.code)
- (SELECT ISNULL(SUM(c1.Credit), 0) FROM [dbo].Chart c1 WHERE c1.Code = c.code)
)T
) oo
where
oo.T >0
and LEFT(c.CODE,3)='401' AND c.Code > 401001
";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(sql2, connection);
//in case you pass #code as a a parameter
//command.Parameters.Add("#code", SqlDbType.Int);
//command.Parameters["#code"].Value = code;
try
{
connection.Open();
var reader = command.ExecuteReader();
while (!reader.IsClosed)
{
DataTable dt = new DataTable();
// Autoload datatable
dt.Load(reader);
Console.WriteLine(dt.Rows.Count);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
You can modify the method and pass code as a parameter
In this case it seems you're looping through and performing multiple queries using multiple Codes, you're also querying Chart twice. In this case you'd want to use a LEFT JOIN from Chart to your other tables.
ON Chart.Code = Salsum.Code
ON Chart.Code = Journal.Code
for example.
You will have to look at GROUP BY as well because you're aggregating some table columns by using SUM.
You may also need to make sure that Code is indexed on the tables you're querying. As long as Code is often queried like this and comparatively rarely Updated or Inserted to, then indexing the Code column on these tables is probably appropriate.
Left Joins : https://technet.microsoft.com/en-us/library/ms187518(v=sql.105).aspx
Indexing: https://technet.microsoft.com/en-us/library/jj835095(v=sql.110).aspx
Sorry I wrote a book on you here, but optimization often leads to a long answer (especially with SQL).
tldr;
Use a LEFT JOIN, grouping by Code
Index the Code columns

SqlDataAdapter.update() not updating database

I am searching for (PostId,UserId) into PostLikes table using SqlDataAdapter, if the row is found , I am using SqlCommandBuilder.GetDeleteCommand() to generate the delete instruction and deleting the underlying row, if the row is not found, then I use SqlCommandBuilder.GetInsertCommand() to generate the insert command and inserting the row to the table using SqlDataAdapter.Update(). But the row is not getting inserted to the table in database. Here is what I have done so far
SqlConnection con = new SqlConnection(connectionStrings);
SqlDataAdapter sqlDataAdapter=new SqlDataAdapter("select * from PostLikes where PostId like "
+postlike.PostId+" and UserId like "
+postlike.UserId,con);
DataSet ds = new DataSet();
sqlDataAdapter.Fill(ds, "Result");
con.Open();
SqlCommandBuilder sqlCommandBuilder = new SqlCommandBuilder(sqlDataAdapter);
if(ds.Tables["Result"].Rows.Count==1)
{
sqlDataAdapter.DeleteCommand = sqlCommandBuilder.GetDeleteCommand(true);
msg = "Data is deleted";
}
else
{
sqlDataAdapter.InsertCommand = sqlCommandBuilder.GetInsertCommand(true);
msg = "Data is inserted";
}
sqlDataAdapter.Update(ds, "Result");
and the tablePostLikes(LikeId,PostId,UserId)
There are a couple of issues:
You are looking to reuse the same command to both detect whether the row exists, and to supply to the SqlAdapter for the SqlCommandBuilder.
You should parameterise the initial select query to protect against SqlInjection attacks (and there is a minor performance benefit). The CommandBuilder will automatically parameterize the Insert / Delete commands
After creating the Insert / Delete commands with the SqlCommandBuilder, you then need to change the underlying dataset in order for any changes to be made to the table during the Update.
Note that many of the Sql objects are IDisposable and should be disposed ASAP - using scopes help here.
.
var postId = 1;
var userId = 1;
string msg;
using (var con = new SqlConnection(#"data source=..."))
using (var selectCommand = new SqlCommand(
"select LikeId, PostId, UserId from PostLikes WHERE PostId=#PostId AND UserId=#UserId", con))
using (var sqlDataAdapter = new SqlDataAdapter(selectCommand))
using (var ds = new DataSet())
{
con.Open();
selectCommand.Parameters.AddWithValue("#PostId", postId);
selectCommand.Parameters.AddWithValue("#UserId", userId);
sqlDataAdapter.Fill(ds, "Result");
using (var sqlCommandBuilder = new SqlCommandBuilder(sqlDataAdapter))
{
if (ds.Tables["Result"].Rows.Count == 1)
{
sqlDataAdapter.DeleteCommand = sqlCommandBuilder.GetDeleteCommand(true);
ds.Tables["Result"].Rows[0].Delete();
msg = "Data will be deleted";
}
else
{
sqlDataAdapter.InsertCommand = sqlCommandBuilder.GetInsertCommand(true);
// Null because LikeId is Identity and will be auto inserted
ds.Tables["Result"].Rows.Add(null, postId, userId);
msg = "Data will be inserted";
}
sqlDataAdapter.Update(ds, "Result");
}
}
I've assumed the following Schema:
CREATE TABLE PostLikes
(
LikeId INT IDENTITY(1,1) PRIMARY KEY,
PostId INT,
UserId INT
)
And I've assumed you want to 'toggle' the insertion or deletion of a row with the postId, userid combination.

To String Conversion while doing Join in LINQ

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
}
}

Tree View Query

I created a query to get all addresses(child) with in municipality(parent) but it is coming back empty/ Any help is appreciated.
drop table #tmp1
go
WITH Emp_CTE AS (
SELECT tablesysID, MunicNo, StreetName
FROM table1
UNION ALL
SELECT e.tablesysID,e.MunicNo,e.StreetName
FROM table1 e
INNER JOIN Emp_CTE ecte ON ecte.MunicNo = e.MunicNo
)
SELECT * into #tmp1
FROM Emp_CTE
select * from #tmp1
it will be used in asp.net tree view control.
Thanks Andomar for your answer, which is correct but I just wanted to share how I solved this problem as follows:
1: make the query as stored procedure that returns xml data type as response like:
create PROCEDURE [dbo].[sp_someproc]
#XmlResponse xml output
AS
BEGIN
--
-- Insert statements for procedure here
set #XmlResponse=(SELECT DISTINCT
table1.MunicNo + ' ' + table1.StreetName + ' ' + table1.City AS firstRow, table1.MunicNo, table1.StreetName, table1.City,
table1.XPOS, table1.YPOS, table1.RollID, table2.Asset_ID, table2.Feature_ID, table2.FeatureName + ',' + table2.Feature_ID + ' ' + table2.[DESC] AS secondRow,
table2.FeatureName, table2.xxxID, table2.[DESC],table3.WONOs, table3.WONOs + ', ' + table3.AssetType + ', ' +table3.Feature_ID AS workONumber
FROM table4 INNER JOIN
table3 ON table4.xxxxID = table3.xxxxID INNER JOIN
table2 ON table4.Asset_ID = table2.xxx_ID INNER JOIN
table1 ON table2.StreetName = table1.StreetName AND table3.MunicNo = table1.MunicNo
for xml auto,root('xml'))
END
select #XmlResponse
2: Aspx page code:
<telerik:RadTreeView ID="rtrvxxxxx" runat="server" >
<DataBindings>
<telerik:RadTreeNodeBinding DataMember="table1" TextField="firstRow" ValueField="firstRow" />
<telerik:RadTreeNodeBinding DataMember="table2" TextField="secondRow" />
<telerik:RadTreeNodeBinding DataMember="table3" TextField="workONumber" />
</DataBindings>
</telerik:RadTreeView>
3: C# Code:
private void loadXmlDocument()
{
try
{
#region Load and Bind xml to treeview
XmlDataSource xDS = new XmlDataSource();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc = callingdatalayerclass.list_XML();
xDS.Data = xmlDoc.InnerXml;
xDS.XPath = "/xml/table1";
xDS.EnableCaching = false;
//bind to treeview
rtrvxxxx.DataSource = xDS;
rtrvxxxx.DataBind();
#endregion
}
catch (Exception ex)
{
ex.Message()}
}
}
4: Data access Layer Code:
public static XmlDocument List_XML()
{
XmlDocument xmlDoc = new XmlDocument();
SqlConnection SQLConn = new SqlConnection();
SQLConn.ConnectionString = someclass.someotherclass.GetConnectionString();
try
{
SQLConn.Open();
SqlCommand custCMD = new SqlCommand("sp_someproc", SQLConn);
custCMD.CommandType = CommandType.StoredProcedure;
custCMD.Parameters.Add("#XmlResponse", SqlDbType.Xml).Direction = ParameterDirection.Output;
custCMD.ExecuteNonQuery();
if (custCMD.Parameters["#XmlResponse"].Value != null)
{
string xml = custCMD.Parameters["#XmlResponse"].Value.ToString();
xmlDoc.LoadXml(xml);
}
return xmlDoc;
}
catch (Exception exGEN)
{
throw exGEN;
}
finally
{
SQLConn.Close();
}
}
Notes: if you see query has rows those are first layer of treeview and 2ndrow is inner row of 1st row or can call it a child of parentnode, 3rd row is inner row or child row of 2nd row, so if 1st row has some records it will output that, if 2nd row has some reocrds it will ouput that. if you see the databining section in treeview datamember is table name and
textfiled is firstrow, value field could be some other coulmn. Have not worked with asp.net orginal treeview so don't know how that works this is for telerik treeview control. I also found that the speed is way faster if data is slected as xml. "DS.XPath = "/xml/table1";" <= this code is selecting xml element or root element and then with in that element the first element which by the data is sorted(first row record's table)
Have a look at your recursive condition:
INNER JOIN Emp_CTE ecte ON ecte.MunicNo = e.MunicNo
This recurses into the same municipality. (Except when MinicNo is null.)
You haven't posted enough information to find the proper condition, but it might look like:
INNER JOIN Emp_CTE ecte ON ecte.tablesysID = e.MunicNo