How do i convert this multiple where cause SQL to eSQL? - entity-framework

T-SQL
USE [AdventureWorks];
SELECT p.* FROM Production.ProductCategory cat ,[Production].[ProductSubcategory] sub, [Production].[Product] p
WHERE cat.ProductCategoryID=1 AND sub.ProductCategoryID = cat.ProductCategoryID and p.ProductSubcategoryID = sub.ProductSubcategoryID
And i want to convert to eSQL for EntityDatasource
<asp:EntityDataSource ID="ProductDataSource" runat="server" ConnectionString="name=AdventureWorksEntities"
DefaultContainerName="AdventureWorksEntities" EntitySetName="Product"
Where="EXISTS(SELECT VALUE cat FROM ProductCategory AS cat WHERE cat.ProductCategoryID=1)
AND EXISTS(SELECT VALUE sub FROM ProductSubcategory AS sub WHERE sub.ProductCategoryID = cat.ProductCategoryID)
AND it.ProductSubcategoryID = sub.ProductSubcategoryID) "
>
</asp:EntityDataSource>
But it is error.
Update :
Thanks devart hints,
I modify the query to
SELECT VALUE p FROM AdventureWorksEntities.ProductCategory AS cat, AdventureWorksEntities.ProductSubcategory AS sub, AdventureWorksEntities.Product AS p WHERE cat.ProductCategoryID=1 AND sub.ProductCategoryID = cat.ProductCategoryID and p.ProductSubcategoryID = sub.ProductSubcategoryID
It work now.

You can use the following code for the Selecting EntityDataSource event handler, for example:
string query = #"SELECT VALUE p FROM EntityContainer.ProductCategory as cat, EntityContainer.ProductSubcategory as sub, EntityContainer.Product as p WHERE cat.ProductCategoryID=1 AND sub.ProductCategoryID = cat.ProductCategoryID and p.ProductSubcategoryID = sub.ProductSubcategoryID";
EntityDataSource source = null;
source = Page.FindControl("ProductDataSource") as EntityDataSource;
if(source != null) {
source.EntitySetName = null;
source.CommandText = query;
}
This code provides a strongly-typed result and uses the Where clause.

Related

Distinct with joins

How do I get distinct rows based on the Last_Name field when my format is as follows:
public ActionResult Index()
{
ResumeDbEntities srd = new ResumeDbEntities();
List<M_Employees> First_Name = srd.M_Employees.ToList();
List<M_Employees> Last_Name = srd.M_Employees.ToList();
List<M_Employees> CurrentLaborCategory = srd.M_Employees.ToList();
List<M_Offices> Location_Number = srd.M_Offices.ToList();
List<M_Offices> City = srd.M_Offices.ToList();
List<M_Offices> State = srd.M_Offices.ToList();
List<S_Emp_Resume> Resume_Name = srd.S_Emp_Resume.ToList();
var multipleTbl = (from p in Resume_Name
join t in Last_Name on p.Employee_Rec_Key equals t.Employee_Rec_Key
join o in Location_Number on t.Office_Rec_Key equals o.Office_Rec_Key
where t.Employee_Rec_Key == 3633
select new MultipleClassRes { M_Employeesdetails = t, S_Emp_Resumedetails = p, M_Officesdetails = o});
return View(multipleTbl);
}
Newly working with MVC but included the auto number from one of the joins.

How to convert an Int to a String inside a LINQ query

I am simply trying to derive an array[] using the following Linq query with EFF and Mysql:
DM_ItemGroup[] array =
(from item_grp in DbContext.hexa_item_group
join item_btn in DbContext.hexa_button
on item_grp.GroupID equals item_btn.ButtonID
where item_btn.ButtonType.Equals("G", StringComparison.Ordinal)
select new DM_ItemGroup
{
GroupID = SqlFunctions.StringConvert((decimal)item_grp.GroupID),
GroupName = item_grp.GroupName,
ButtonID = item_btn.ButtonID,
Default_TaxId = item_grp.Default_TaxId,
Out_Of_Sales = item_grp.Out_Of_Sales,
Sales_Seq = item_grp.Sales_Seq,
DataModel_Button = new DM_Button(),
}).ToArray<DM_ItemGroup>();
I initially tried .ToString() but it gave an exception. After trying SqlFunctions.StringConvert I am getting the following error:-
The specified method 'System.String StringConvert(System.Nullable`1[System.Decimal])'
on the type 'System.Data.Objects.SqlClient.SqlFunctions'
cannot be translated into a LINQ to Entities store expression.
How to convert the GroupID (which is a Int in my Table) to String (which is required by my DataModel)?
Thanks for down voting a perfectly legitimate question.Wish someone had answered the question with equal promptness.
I found the solution to my problem which is as follows:-
using (HexaEntities hh=new HexaEntities())
{
var cc = hh.hexa_item_group.ToDictionary(k => k.GroupID, k => k);
var lst = from l in cc
orderby l.Key
select new DM_ItemGroup {GroupID = l.Key.ToString(), GroupName = l.Value.GroupName, Default_TaxId=l.Value.Default_TaxId,ButtonID=l.Value.ButtonID.Value,Out_Of_Sales=l.Value.Out_Of_Sales,Sales_Seq=l.Value.Sales_Seq };
AllRecords = lst.ToList<DM_ItemGroup>();
}

How to avoid writing duplicate queries when needing counts and then items

I have constructed a LINQ query that joins about a half dozen tables. The problem is, for paging purposes, I want to get a count first of how many items will be returned. So the issue I'm running into is having to write the exact same query twice: one to get the item count then another to build my collection of items.
Example:
using (var context = new DbContext())
{
var items = from i in context.Table1
join a in context.TableA on i.SomeProperty equals a.SomeProperty
join b in context.TableB on i.SomeOtherProperty equals b.SomeProperty
join c in context.TableC on i.AnotherProperty equals c.SomeProperty
etc.
etc.
select i;
count = items.Count();
}
return count;
.
.
.
using (var context = new DbContext())
{
var items = from i in context.Table1
join a in context.TableA on i.SomeProperty equals a.SomeProperty
join b in context.TableB on i.SomeOtherProperty equals b.SomeProperty
join c in context.TableC on i.AnotherProperty equals c.SomeProperty
etc.
etc.
select new
{
DynamicProp1 = i.SomeProperty,
DyanmicProp2 = a.SomeProperty,
DyanmicProp3 = b.SomePropery,
etc.
etc.
}
... do some stuff with 'items'...
}
I cannot think of any way to avoid this duplicate query. I need access to all the joined tables in order to build my collection. I would appreciate any tips or suggestions.
You can create method which get context and return IQueryable of items with all needed entities:
class Holder
{
TableAItem A{get;set;}
TableBItem B{get;set;}
...
}
IQueryable<Holder> GetQuery(DbContext context)
{
return from i in context.Table1
join a in context.TableA on i.SomeProperty equals a.SomeProperty
join b in context.TableB on i.SomeOtherProperty equals b.SomeProperty
join c in context.TableC on i.AnotherProperty equals c.SomeProperty
...
select new Holder
{
A = i,
B = b
....
};
}
using (var context = new DbContext())
{
var items = GetQuery(context);
count = items.Count();
}
return count;
using (var context = new DbContext())
{
var items = from r in GetQuery(context)
select new
{
DynamicProp1 = r.a.SomeProperty,
DyanmicProp2 = r.a.SomeProperty,
DyanmicProp3 = r.b.SomePropery,
etc.
etc.
}
... do some stuff with 'items'...
}
Remember that making a query doesn't execute it, this is called deferred execution. So why not make the query and then pass it around as an IQueryable<> object. For example, consider this code:
Just a simple method to return the last char from a string, but it also writes out what it's doing:
public char GetLastChar(string input)
{
Console.WriteLine("GetLastChar from {0}", input);
return input.Last();
}
Now this code using the method:
var listOfStuff = new List<string> { "string1", "string2", "string3" };
Console.WriteLine("Making the query");
var results = from s in listOfStuff
select GetLastChar(s);
Console.WriteLine("Before getting count");
var count = results.Count();
Console.WriteLine("Now enumerating the query");
foreach(var s in results)
{
Console.WriteLine(s);
}
You will see the output as follows:
Making the query
Before getting count
GetLastChar from string1
GetLastChar from string2
GetLastChar from string3
3
Now enumerating the query
GetLastChar from string1
1
GetLastChar from string2
2
GetLastChar from string3
3

Processing multiple result-sets returned from a stored procedure in Entity Framework

I have a stored procedure like this :
CREATE STORED PROCEDURE Test1
AS
BEGIN
SELECT * FROM Table1
SELECT * FROM Table2
END
Now I want to use this procedure in EF.How?! can I use both two SELECT requests returned from procedure in EF ?!
Note : I know how can I use this stored procedure if it returns just on result
Thanks
Here is the answer your question
using (var db = new EF_DEMOEntities())
{
var cmd = db.Database.Connection.CreateCommand();
cmd.CommandText = "[dbo].[proc_getmorethanonetable]";
try
{
db.Database.Connection.Open();
using (var reader = cmd.ExecuteReader())
{
var orders = ((IObjectContextAdapter)db).ObjectContext.Translate<Order>(reader);
GridView1.DataSource = orders.ToList();
GridView1.DataBind();
reader.NextResult();
var items =
((IObjectContextAdapter)db).ObjectContext.Translate<Item>(reader);
GridView2.DataSource = items.ToList();
GridView2.DataBind();
reader.NextResult();
var collect = ((IObjectContextAdapter)db).ObjectContext.Translate<object>(reader);
GridView3.DataSource = collect.ToList();
GridView3.DataBind();
}
}
finally
{
db.Database.Connection.Close();
}
}

using the TSqlParser

I'm attempting to parse SQL using the TSql100Parser provided by microsoft. Right now I'm having a little trouble using it the way it seems to be intended to be used. Also, the lack of documentation doesn't help. (example: http://msdn.microsoft.com/en-us/library/microsoft.data.schema.scriptdom.sql.tsql100parser.aspx )
When I run a simple SELECT statement through the parser it returns a collection of TSqlStatements which contains a SELECT statement.
Trouble is, the TSqlSelect statement doesn't contain attributes such as a WHERE clause, even though the clause is implemented as a class. http://msdn.microsoft.com/en-us/library/microsoft.data.schema.scriptdom.sql.whereclause.aspx
The parser does recognise the WHERE clause as such, looking at the token stream.
So, my question is, am I using the parser correctly? Right now the token stream seems to be the most useful feature of the parser...
My Test project:
public static void Main(string[] args)
{
var parser = new TSql100Parser(false);
IList<ParseError> Errors;
IScriptFragment result = parser.Parse(
new StringReader("Select col from T1 where 1 = 1 group by 1;" +
"select col2 from T2;" +
"select col1 from tbl1 where id in (select id from tbl);"),
out Errors);
var Script = result as TSqlScript;
foreach (var ts in Script.Batches)
{
Console.WriteLine("new batch");
foreach (var st in ts.Statements)
{
IterateStatement(st);
}
}
}
static void IterateStatement(TSqlStatement statement)
{
Console.WriteLine("New Statement");
if (statement is SelectStatement)
{
PrintStatement(sstmnt);
}
}
Yes, you are using the parser correctly.
As Damien_The_Unbeliever points out, within the SelectStatement there is a QueryExpression property which will be a QuerySpecification object for your third select statement (with the WHERE clause).
This represents the 'real' SELECT bit of the query (whereas the outer SelectStatement object you are looking at has just got the 'WITH' clause (for CTEs), 'FOR' clause (for XML), 'ORDER BY' and other bits)
The QuerySpecification object is the object with the FromClauses, WhereClause, GroupByClause etc.
So you can get to your WHERE Clause by using:
((QuerySpecification)((SelectStatement)statement).QueryExpression).WhereClause
which has a SearchCondition property etc. etc.
Quick glance around would indicate that it contains a QueryExpression, which could be a QuerySpecification, which does have the Where clause attached to it.
if someone lands here and wants to know how to get the whole elements of a select statement the following code explain that:
QuerySpecification spec = (QuerySpecification)(((SelectStatement)st).QueryExpression);
StringBuilder sb = new StringBuilder();
sb.AppendLine("Select Elements");
foreach (var elm in spec.SelectElements)
sb.Append(((Identifier)((Column)((SelectColumn)elm).Expression).Identifiers[0]).Value);
sb.AppendLine();
sb.AppendLine("From Elements");
foreach (var elm in spec.FromClauses)
sb.Append(((SchemaObjectTableSource)elm).SchemaObject.BaseIdentifier.Value);
sb.AppendLine();
sb.AppendLine("Where Elements");
BinaryExpression binaryexp = (BinaryExpression)spec.WhereClause.SearchCondition;
sb.Append("operator is " + binaryexp.BinaryExpressionType);
if (binaryexp.FirstExpression is Column)
sb.Append(" First exp is " + ((Identifier)((Column)binaryexp.FirstExpression).Identifiers[0]).Value);
if (binaryexp.SecondExpression is Literal)
sb.Append(" Second exp is " + ((Literal)binaryexp.SecondExpression).Value);
I had to split a SELECT statement into pieces. My goal was to COUNT how many record a query will return. My first solution was to build a sub query such as
SELECT COUNT(*) FROM (select id, name from T where cat='A' order by id) as QUERY
The problem was that in this case the order clause raises the error "The ORDER BY clause is not valid in views, inline functions, derived tables, sub-queries, and common table expressions, unless TOP or FOR XML is also specified"
So I built a parser that split a SELECT statment into fragments using the TSql100Parser class.
using Microsoft.Data.Schema.ScriptDom.Sql;
using Microsoft.Data.Schema.ScriptDom;
using System.IO;
...
public class SelectParser
{
public string Parse(string sqlSelect, out string fields, out string from, out string groupby, out string where, out string having, out string orderby)
{
TSql100Parser parser = new TSql100Parser(false);
TextReader rd = new StringReader(sqlSelect);
IList<ParseError> errors;
var fragments = parser.Parse(rd, out errors);
fields = string.Empty;
from = string.Empty;
groupby = string.Empty;
where = string.Empty;
orderby = string.Empty;
having = string.Empty;
if (errors.Count > 0)
{
var retMessage = string.Empty;
foreach (var error in errors)
{
retMessage += error.Identifier + " - " + error.Message + " - position: " + error.Offset + "; ";
}
return retMessage;
}
try
{
// Extract the query assuming it is a SelectStatement
var query = ((fragments as TSqlScript).Batches[0].Statements[0] as SelectStatement).QueryExpression;
// Constructs the From clause with the optional joins
from = (query as QuerySpecification).FromClauses[0].GetString();
// Extract the where clause
where = (query as QuerySpecification).WhereClause.GetString();
// Get the field list
var fieldList = new List<string>();
foreach (var f in (query as QuerySpecification).SelectElements)
fieldList.Add((f as SelectColumn).GetString());
fields = string.Join(", ", fieldList.ToArray());
// Get The group by clause
groupby = (query as QuerySpecification).GroupByClause.GetString();
// Get the having clause of the query
having = (query as QuerySpecification).HavingClause.GetString();
// Get the order by clause
orderby = ((fragments as TSqlScript).Batches[0].Statements[0] as SelectStatement).OrderByClause.GetString();
}
catch (Exception ex)
{
return ex.ToString();
}
return string.Empty;
}
}
public static class Extension
{
/// <summary>
/// Get a string representing the SQL source fragment
/// </summary>
/// <param name="statement">The SQL Statement to get the string from, can be any derived class</param>
/// <returns>The SQL that represents the object</returns>
public static string GetString(this TSqlFragment statement)
{
string s = string.Empty;
if (statement == null) return string.Empty;
for (int i = statement.FirstTokenIndex; i <= statement.LastTokenIndex; i++)
{
s += statement.ScriptTokenStream[i].Text;
}
return s;
}
}
And to use this class simply:
string fields, from, groupby, where, having, orderby;
SelectParser selectParser = new SelectParser();
var retMessage = selectParser.Parse("SELECT * FROM T where cat='A' Order by Id desc",
out fields, out from, out groupby, out where, out having, out orderby);