So I'm trying to figure out of this, in particular I have this query that perfectly works using PhpMyAdmin:
SELECT tt.team_id, (CASE WHEN t.id IS NULL THEN 0 ELSE 1 END) as exist FROM(SELECT 13048 as team_id UNION ALL SELECT 17058 UNION ALL SELECT 38809 UNION ALL SELECT 8216 UNION ALL SELECT 5466) tt LEFT JOIN team t on t.id = tt.team_id WHERE t.id IS NULL OR t.update_at < DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)
Anyway, I get this error from Visual Studio:
MySql.Data.MySqlClient.MySqlException: 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' UNION ALL SELECT 17058 UNION ALL SELECT 38809 UNION ALL SELECT 8216 UNION ALL ' at line 1'
This error is retured on:
using (MySqlDataReader reader = command.ExecuteReader())
I setup the query in this way:
command.CommandText = "SELECT tt.team_id, " +
"(CASE WHEN t.id IS NULL THEN 0 ELSE 1 END) as exist " +
"FROM(SELECT #first as team_id #others) tt LEFT JOIN team t on t.id = tt.team_id " +
"WHERE t.id IS NULL OR " +
"t.update_at < DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)";
command.Parameters.Add("#first", MySqlDbType.Int32).Value = teams.First().Id;
command.Parameters.Add("#others", MySqlDbType.String).Value = string.Concat(teams.Skip(1).Select(c => " UNION ALL SELECT " + c.Id));
Someone could help me?
This is how I would build a dynamic list of parameters to pass to your query.
Warning, not tested, but this should produce the expected output
// Command text with a placeholder where we insert the dynamic text
string cmd = #"SELECT tt.team_id,
(CASE WHEN t.id IS NULL THEN 0 ELSE 1 END) as exist
FROM (SELECT {texttoreplace}) tt
LEFT JOIN team t on t.id = tt.team_id WHERE t.id IS NULL
OR t.update_at < DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)";
int prmCounter = 1;
// Where we keep the text to insert at the appropriate place
StringBuilder unions = new StringBuilder();
// Where we keep the parameters to add at the MySqlCommand
List<MySqlParameter> prms = new List<MySqlParameter>();
// First parameter
MySqlParameter pr = new MySqlParameter("#first", MySqlDbType.Int32) { Value = teams.First().id};
prms.Add(pr);
unions.Append($" #first as team_id ");
// Loop over your IDs and build parameters and text
foreach (var t in teams.Skip(1))
{
// Giving an unique name to the parameter
string placeholder = "#p" + prmCounter;
unions.Append($" UNION ALL SELECT {placeholder}");
pr = new MySqlParameter(placeholder, MySqlDbType.Int32) { Value = t.id};
prms.Add(pr);
prmCounter++;
}
// Add all the required parameters
command.Parameters.AddRange(prms.ToArray());
// Replace the placeholder with the built text
cmd = cmd.Replace("{texttoreplace}", unions.ToString());
Related
How does a SQL Server query select from parameter? I just want to make it simple set select column based on my C# code. Is it possible?
Here is my stored procedure:
ALTER PROCEDURE [dbo].[GetMembersDetailGenerateChanceTop10000]
#EventId nvarchar(255),
#PeriodId nvarchar(255),
#QueryParam nvarchar(1000)
AS
BEGIN
SET NOCOUNT ON;
SELECT DISTINCT TOP 10000 #QueryParam
FROM ign..Chance_Generated cg
INNER JOIN ign..Contact c ON cg.ContactID = c.ContactId
LEFT JOIN ign..CustomerAddress ca ON ca.parentid = cg.contactid
LEFT JOIN ign..new_cardlevelconfig cl ON cl.new_cardlevelconfigid = c.new_cardlevel
LEFT JOIN ign..new_country co ON co.new_countryid = c.new_country
LEFT JOIN ign..new_province po ON po.new_provinceId = c.new_Province
LEFT JOIN ign..StringMap sm ON sm.AttributeValue = c.new_IDType
LEFT JOIN ign..new_city cy ON cy.new_cityId = c.new_CityCounty
LEFT JOIN ign..new_transactionheader th ON cg.New_Name COLLATE DATABASE_DEFAULT = th.new_name COLLATE DATABASE_DEFAULT
WHERE cg.EventId = #EventId
AND (ca.AddressNumber = '1' OR ca.AddressNumber IS NULL)
AND (sm.AttributeName IS NULL OR sm.AttributeName = 'new_idtype')
AND cg.periodId = #PeriodId
QueryParam, EventId, PeriodId will be filled from C# code.
Here is my C# code:
private List<GenerateModel> getDataTopFromStoreProcedure(string EventId, string PeriodId)
{
// query select parameter
string QueryParam = #"cg.Chance_Number, th.new_name as [th name], dateadd(HOUR,7,th.createdon) as [th createdon],
c.new_Initial, c.FirstName, c.LastName";
string ConnString = GenerateChance.Properties.Settings.Default["DB_ConnectionString"].ToString();
using (SqlConnection conn = new SqlConnection(ConnString))
{
SqlCommand cmd = new SqlCommand();
cmd.CommandText = GetMembersDetailGenerateChanceTop10000;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 0; //no limit
cmd.Parameters.Clear();
cmd.Parameters.Add(new SqlParameter("QueryParam", QueryParam));
cmd.Parameters.Add(new SqlParameter("EventId", EventId));
cmd.Parameters.Add(new SqlParameter("PeriodId", PeriodId));
cmd.Connection = conn;
if (conn.State == ConnectionState.Open)
conn.Close();
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
list.Add(new GenerateModel
{
ChanceNumber = reader["Chance_Number"].ToString(), //System.IndexOutOfRangeException Error
Receipt = reader["th name"].ToString(),
Date = reader["th createdon"].ToString(),
Initial = reader["new_Initial"].ToString(),
FirstName = reader["FirstName"].ToString(),
LastName = reader["LastName"].ToString(),
});
}
reader.Close();
}
}
return list;
}
I am confused as to how to implement his method because I want to get return of all select results in object model but I always get error
System.IndexOutOfRangeException : Chance_Number.
Honestly why do I use query select parameter is because I want to get value from checkedListBox1 that already I defined before by using this code get all checkedListBox1 value to determine select query.
string QueryParam = "cg.Chance_Number";//auto get chance_number as select mandatory
for (int i = 0; i < checkedListBox1.CheckedItems.Count; i++)
{
QueryParam += ", " + ((clsItemList)checkedListBox1.CheckedItems[i]).Value;
}
You have to use constructor with proper length for parameters as given below, to avoid the issue.Read more on SQLParameter
public SqlParameter (string parameterName, System.Data.SqlDbType dbType, int size);
cmd.Parameters.Add(new SqlParameter("QueryParam", SqlDbType.NVarChar,1000)).Value = QueryParam;
You need to make few more changes:
The way you have defined the procedure is wrong. You have to define the procedure as dynamic sql for the #queryparam to get concatenated to the SELECT query as given below:
DECLARE #selectStmt NVARCHAR(MAX) = ''
DECLARE #sqldefinition NVARCHAR(4000) = '#EventId nvarchar(255), #PeriodId nvarchar(255)'
SET #selectStmt += 'select distinct top 10000 ' + #QueryParam +
'from ign..Chance_Generated cg
inner join ign..Contact c on cg.ContactID = c.ContactId
left join ign..CustomerAddress ca on ca.parentid = cg.contactid
left join ign..new_cardlevelconfig cl on cl.new_cardlevelconfigid = c.new_cardlevel
left join ign..new_country co on co.new_countryid = c.new_country
left join ign..new_province po on po.new_provinceId = c.new_Province
left join ign..StringMap sm on sm.AttributeValue = c.new_IDType
left join ign..new_city cy on cy.new_cityId = c.new_CityCounty
left join ign..new_transactionheader th on cg.New_Name COLLATE DATABASE_DEFAULT = th.new_name COLLATE DATABASE_DEFAULT
where cg.EventId= '''+ #EventId +''' and (ca.AddressNumber = ''1'' or ca.AddressNumber is null) and (sm.AttributeName is null or sm.AttributeName = ''new_idtype'')
and cg.periodId = ''' + #PeriodId + ''';'
EXEC #sp_executesql #selectStmt, #sqldefinition, #EventId , #PeriodId
``
- Always refer the tables with proper schema in the query
ign.SchemaName.new_country
ign.SchemaName.new_province
The following stored procedure displays three strings and a table row result as output.
Is there any way we can display all the results on a mvc view output panel using entity framework?
I could see the first string result in the code below. But is there anyway to get the other two select string outputs and
the table row result.
private CustomerEntities db = new CustomerEntities();
public ActionResult Index()
{
var results = db.usp_CustomerData("124544", 1500);
var abc = results.ToList();
return View();
}
ALTER PROCEDURE [dbo].[usp_CustomerData]
#CustomerID varchar(6),
#MinsBack int
AS
BEGIN
DECLARE #Count int
SET #Count = (SELECT Count(*)
FROM Customer WITH (NOLOCK)
WHERE CustomerID = #CustomerID AND
DATEDIFF(mi, ReceivedAt, GETUTCDATE()) < #MinsBack)
IF (#Count = 1)
SELECT 'Ok: 1 message in Customer table'
ELSE
SELECT 'ERROR: Expected 1 message in Customer table, but found ' + CONVERT(varchar(3), #Count) + ' messages.'
SET #Count = (SELECT Count(*)
FROM CustomerDetails WITH (NOLOCK)
WHERE CustomerID = #CustomerID AND
DATEDIFF(mi, LastUpdatedAt, GETDATE()) < #MinsBack)
IF (#Count = 1)
SELECT 'Ok: 1 record in CustomerDetails table'
ELSE
SELECT 'ERROR: Expected 1 record in CustomerDetails table, but found ' + CONVERT(varchar(3), #Count) + ' records.'
SET #Count = (SELECT Count(*)
FROM CustomerProduct WITH (NOLOCK)
WHERE CustomerID = #CustomerID AND
DATEDIFF(mi, LastUpdatedAt, GETDATE()) < #MinsBack)
IF (#Count = 1)
SELECT 'Ok: 1 record in CustomerProduct table'
ELSE
SELECT 'ERROR: Expected 1 record in CustomerProduct table, but found ' + CONVERT(varchar(3), #Count) + ' records.'
SELECT *FROM Customer where customerID = #CustomerID
END
As suggestion you could create a temporary table in your SQL script which will be used as temporary store.
CREATE TABLE #Results
(
Message VARCHAR(512)
)
Instead of a direct SELECT in each IF or ELSE you should insert the string into the temp table.
At the end you could reach your goal to get all inserted strings to return them by:
SELECT * FROM #Results
To get customers - like you do at the end - you should trigger a new query to database.
Depending on your case you should consider to querying the database by data context instead of querying the database by store procedures.
You need to do something as suggest in this link but I summarized below
For each results set you will need to do a reader.NextResult();
var someReturnObject = new ResultObject();
using (var context = new LinqPadDbContext(#"Server=localhost\SQLEXPRESS;Database=StackOverflow;Trusted_Connection=True;"))
{
var cmd = context.Database.Connection.CreateCommand();
cmd.CommandText = "[dbo].[GetSomeData]";
try
{
context.Database.Connection.Open();
var reader = cmd.ExecuteReader();
var result1 = ((IObjectContextAdapter)context).ObjectContext.Translate<string>(reader);
someResultObject.Text1 = result1.First();
//for each extra result, start here
reader.NextResult();
var users = ((IObjectContextAdapter)context).ObjectContext.Translate<User>(reader);
someResultObject.Users = users.Select(x => x);
//stop here
}
finally
{
context.Database.Connection.Close();
}
}
SELECT
wl.WatchListId, wl.Code, wl.[Description], wl.DateCreated,
wl.CreatedBy, wl.DateModified, wl.ModifiedBy,
wpi.ParameterExpression as IndividualExpression,
wpb.ParameterExpression as BusinessExpression,
wpd.ParameterExpression as DefaultExpression,
CASE
WHEN EXISTS(SELECT 1 FROM SourceWatchList
WHERE SourceId = #SourceId AND WatchListId = wl.WatchListId)
THEN 1 ELSE 0
END AS IsActive
FROM
[WatchList] wl
LEFT JOIN
SourceWatchList swl ON wl.WatchListId = swl.WatchListId AND swl.SourceId = #SourceId
LEFT JOIN
(SELECT
ParameterExpression, SourceId, WatchListId
FROM WatchListParameter
WHERE EntityType = 'INDIVIDUAL') wpi ON wpi.SourceId = #SourceId
AND wpi.WatchListId = wl.WatchListId
LEFT JOIN
(SELECT
ParameterExpression, SourceId, WatchListId
FROM WatchListParameter
WHERE EntityType = 'BUSINESS') wpb ON wpb.SourceId = #SourceId
AND wpb.WatchListId = wl.WatchListId
LEFT JOIN
(SELECT ParameterExpression, SourceId, WatchListId
FROM WatchListParameter
WHERE EntityType = 'DEFAULT') wpd ON wpd.SourceId = #SourceId
AND wpd.WatchListId = wl.WatchListId
WHERE
wl.IsActive = 1
I have the above query. Pretty simple.
Here's a snippet from SQL Server Management Studio table :
and from the debugger in Visual Studio :
The Visual Studio table has no data in the 3 Expression Columns while the Management Studio (correctly) does. Can any tell me why that is, and what steps I can take to resolve the issue?
I'm 100% sure I've used the same parameter between the two as well.
string sql = #"SELECT wl.WatchListId,wl.Code,wl.[Description],wl.DateCreated,
wl.CreatedBy,wl.DateModified,wl.ModifiedBy,
wpi.ParameterExpression as IndividualExpression,
wpb.ParameterExpression as BusinessExpression,
wpd.ParameterExpression as DefaultExpression,
CASE WHEN EXISTS(Select 1 FROM SourceWatchList
WHERE SourceId = #SourceId AND WatchListId = wl.WatchListId)
THEN 1 ELSE 0 END AS IsActive
FROM [WatchList] wl
LEFT JOIN SourceWatchList swl on wl.WatchListId = swl.WatchListId and swl.SourceId = #SourceId
LEFT JOIN (Select ParameterExpression, SourceId, WatchListId FROM WatchListParameter WHERE EntityType = 'INDIVIDUAL') wpi
ON wpi.SourceId = #SourceId AND wpi.WatchListId = wl.WatchListId
LEFT JOIN (Select ParameterExpression, SourceId, WatchListId FROM WatchListParameter WHERE EntityType = 'BUSINESS') wpb
ON wpb.SourceId = #SourceId AND wpb.WatchListId = wl.WatchListId
LEFT JOIN (Select ParameterExpression, SourceId, WatchListId FROM WatchListParameter WHERE EntityType = 'DEFAULT') wpd
ON wpd.SourceId = #SourceId AND wpd.WatchListId = wl.WatchListId
where wl.IsActive = 1";
SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["WatchListCompliance"].ConnectionString);
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("#SourceId", SourceId);
DataTable dt = new DataTable();
using (SqlDataAdapter a = new SqlDataAdapter(cmd))
{
a.Fill(dt);
}
This might be a problem with types and equality. You can try using SqlDataType when you define the parameters on the sqlcommand. When you use addwithvalue without declaring a type it could be selecting the wrong type. Then you should use the type you declared in the sql expression.
cmd.Parameters.Add("#SourceId", SqlDbType.VarChar, 20);
cmd.Parameters["#SourceId"].Value = SourceId;
Wild guess: are you sure your session is configured the same way? Especially the SET ANSI_NULLS option, which changes how comparison behaves with regard to null values.
It is worth noting that some databases may have unusual default values, but some clients (e.g. ADO.NET) explicitely define their own values for the session when they connect, even if you don't ask them to.
I try to input value but #numVal doest not work ( on the line begin with arr[10] )
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MySql.Data.MySqlClient;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
MySqlConnection conDatabase = new MySqlConnection("Data Source=localhost;" +
"Persist Security Info=yes;" +
"UserId=tee; PWD=t5794849; database=ph3;");
conDatabase.Open();
// MySqlCommand cmdDatabase = new MySqlCommand("DROP TABLE IF EXISTS `q_mem_sur`; create table q_mem_sur as SELECT Count(*) As rowa, member.Ssurname, Sum(Case When ((member.status = '1')) Then 1 Else 0 End) As Status11 From member Group By member.Ssurname Order By rowa Desc;", conDatabase);
Console.WriteLine("Enter username");
string input = Console.ReadLine();
try
{
int numVal = Convert.ToInt16(input);
}
catch (FormatException )
{
Console.WriteLine("Input string is not a sequence of digits.");
}
catch (OverflowException )
{
Console.WriteLine("The number cannot fit in an Int32.");
}
string[] arr = new string[11];
arr[0] = "UPDATE `member` SET `amphurecode`= SUBSTRING(member.own,3,4)";
arr[1] = "UPDATE `member` SET `provincecode`= SUBSTRING(member.own,3,2)";
arr[2] = "DROP TABLE IF EXISTS `q_mem_tim`; create table q_mem_tim as SELECT member.idmember, member.own, member.provincecode, province.PROVINCE_NAME, member.amphurecode, amphur.AMPHUR_NAME, member.novote, member.Sname, member.Ssurname, member.Hno, member.Moo, member.Sex, member.tambol, member.dateofbirth, member.migratedate, Year( Current_Date( ) ) - Year( member.dateofbirth ) AS y, DATEDIFF('2011-08-01',(migratedate)) AS d FROM member LEFT JOIN amphur ON ( member.amphurecode = amphur.AMPHUR_CODE ) LEFT JOIN province ON member.provincecode = province.PROVINCE_CODE";
arr[3] = "DROP TABLE IF EXISTS `q_mem_sur`; create table q_mem_sur as SELECT Count(*) As rowa, member.Ssurname, Sum(Case When ((member.status = '1')) Then 1 Else 0 End) As Status11 From member Group By member.Ssurname Order By rowa Desc";
arr[4] = "DROP TABLE IF EXISTS `q_mem_hno` ; create table q_mem_hno as select member.Hno, member.Moo, member.tambol, COUNT( member.Hno ) AS cntHno, COUNT(DISTINCT member.Ssurname) as NoSur FROM member GROUP BY member.Hno, member.Moo, member.tambol ORDER BY cntHno DESC ";
arr[5] = "DROP TABLE IF EXISTS `q_pro_ori`; create table q_pro_ori as Select member.provincecode, count(*) As cnt From member Group By member.provincecode Order By cnt Desc ";
arr[6] = "DROP TABLE IF EXISTS `q_am_ori`; create table q_am_ori as Select member.amphurecode, member.provincecode, count(*) As cnt From member Group By member.amphurecode, member.provincecode Order By cnt Desc ";
arr[7] = "DROP TABLE IF EXISTS `Sur_Hno_`; create table Sur_Hno_ as SELECT count( * ) , Ssurname, q_mem_tim.Hno, q_mem_tim.Moo, q_mem_tim.tambol FROM q_mem_tim GROUP BY q_mem_tim.Ssurname, q_mem_tim.Hno, q_mem_tim.Moo, q_mem_tim.tambol ORDER BY count( * ) DESC";
arr[8] = "DROP TABLE IF EXISTS `q_dup_own`; create table q_dup_own as SELECT Count(*) as n ,member.own FROM member GROUP BY member.own order by n DESC ";
// arr[9] = "drop table if exists q_mem_birth; create table q_mem_birth as SELECT member.idmember, member.own, member.provincecode, province.PROVINCE_NAME, member.amphurecode, amphur.AMPHUR_NAME, member.Sname, member.Ssurname, member.Hno, member.Moo, member.Sex, member.tambol, member.dateofbirth, member.migratedate, member.fathercode , member.mathercode, Year( Current_Date( ) ) - Year( member.dateofbirth ) AS y, DATEDIFF('2011-08-01',(migratedate)) AS d ,member.inputstaf FROM member LEFT JOIN amphur ON ( member.amphurecode = amphur.AMPHUR_CODE ) LEFT JOIN province ON member.provincecode = province.PROVINCE_CODE WHERE DAYOFYEAR(member.dateofbirth)-DAYOFYEAR(NOW()) < 30 and DAYOFYEAR(member.dateofbirth)-DAYOFYEAR(NOW()) > -1 order by DAYOFYEAR(member.dateofbirth)";
arr[9] = "ALTER TABLE `q_mem_tim` ADD `agec` VARCHAR( 10 ) NULL ";
// arr[10] = "UPDATE q_mem_birth SET agec = CASE WHEN y < 10 THEN 'ด' WHEN y > 10 and y < 20 and Sex='ญ' THEN 'วญ' WHEN y > 10 and y < 20 and Sex='ช' THEN 'วช' ELSE 'ผญ' END";
arr[10] = "drop table if exists q_mem_birth; create table q_mem_birth as SELECT q_mem_tim.idmember,q_mem_tim.own,q_mem_tim.PROVINCE_NAME,q_mem_tim.AMPHUR_NAME,q_mem_tim.novote,q_mem_tim.Sname,q_mem_tim.Ssurname,q_mem_tim.Hno,q_mem_tim.Moo,q_mem_tim.Sex,q_mem_tim.tambol,q_mem_tim.dateofbirth,q_mem_tim.migratedate,q_mem_tim.y,q_mem_tim.d,q_mem_tim.agec FROM q_mem_tim where q_mem_tim.dateofbirth is not null and q_mem_tim.dateofbirth != '00000000' and day(q_mem_tim.dateofbirth) != '00' and day(q_mem_tim.dateofbirth) > 0 and day(q_mem_tim.dateofbirth) < 11 and month(q_mem_tim.dateofbirth) != '00' and month(q_mem_tim.dateofbirth) = #numVal order by tambol,Moo, month(dateofbirth),day(dateofbirth) ";
foreach (string s in arr)
{
Console.WriteLine(s);
MySqlCommand cmdDbase = new MySqlCommand((s), conDatabase);
cmdDbase.CommandTimeout = 500;
cmdDbase.ExecuteNonQuery();
}
conDatabase.Close();
}
}
}
1)Truncate the tables; don't drop them and remake them because when you drop them you have to do the indexes and add the Primary Keys again.
using(var cm = _dbConnection.CreateCommand())
{
cm.CommandText = #"Truncate Table Table";
cm.CommandType = CommandType.Text;
cm.ExecuteNonQuery();
}
2)Don't forget the # symbol; it helps with anything SQL:
using(var cm = _dbConnection.CreateCommand())
{
cm.CommandText = #"Select *
From table
Where Id = #Id";
cm.CommandType = CommandType.Text;
cm.Parameter.AddWithValue("Id", id);
cm.ExecuteNonQuery();
}
I know you're not doing it this way and you're using a string array (just put a foreach loop outside the using statement and replace the cm.CommandText value with the string's value) but with the examples it should help you or at least give you some ideas.
You need to add a MySqlParameter to the command named numVal.
I have 3 tables that I need to use:
Brand-
BrandID
Name
BrandSource-
BrandID
SourceID
Source-
SourceID
SourceName
Image
So I have a many -many relationship with BrandSource being my intermediate table. I have each Brand column displayed in a table and I made a new column for the source image. Essentially, if there is 5 sources for one brand I need it to show one row for the brand and the 5 different source images in the new column I made.(5 images in one cell).
Since I have joined the three tables it obviously sees that there is 5 rows in the BrandSource table and displays 5 rows of each brand with a single source image in a cell.
I'm sure I could select distinct brands, but that still doesn't solve my problem of how I can get all of the source images for each brand to show up in the same cell.
Here is my linq code:(As you can see there is some info in here that I left out above for brevity).
var join = from b in db.Brands
join bs in db.Brands_Sources on b.BrandID equals bs.BrandID
join sb in db.Sources on bs.SourceID equals sb.SourceID
select new { Brand = b, source = sb.Image, c = b.Description.Length < 204 ? b.Description : b.Description.Substring(0, 204) + "..." };
And here is how i'm using it:
foreach (var result in join)
{
bool a = result.Brand.Active;
string chk = string.Empty;
if (a == true)
chk = "checked='checked'";
else
chk = "";
resultSpan.InnerHtml += "<tr><td><input type='checkbox' " + chk + "></td><td width='1%'><img width='50px' src='" + result.Brand.Image + "'</img></td>" +
"<td>" + result.Brand.Name + "</td><td width='60%'>" + result.c + "</td><td><img src='"+result.source+"'></img></td><td>" + result.Brand.DateCreated + "</td><td>" + result.Brand.DateModified + "</td></tr>";
}
You've got a good start, but I think you'd be better served not doing the triple join yourself. Linq-to-sql can handle the details of that for you. If you back away from the query aspect for a second and start with your desired result, you'll do better. From what I can tell, the object type you want out of this is a list of Brands, and each Brand should contain a list of its sources. Here's how you do it (starting with downloading LinqPad)...
// LinqPad C# statement(s)
var results =
from b in Brands
select new {
Brand = b,
Sources = (
from s in Sources
join xref in BrandSources on s.SourceID equals xref.SourceID
where xref.BrandID == b.BrandID
select s
).ToList()
};
result.Dump(); // show result in LinqPad
LinqPad shows that this executes in a single query, but the guts of assembling your List<Source> in your result object happens behind the scenes. Here's what LinqPad executes:
SELECT [t0].[BrandID], [t0].[Name], [t1].[SourceID], [t1].[SourceName], [t1].[Image], (
SELECT COUNT(*)
FROM [Source] AS [t3]
INNER JOIN [BrandSource] AS [t4] ON [t3].[SourceID] = [t4].[SourceID]
WHERE [t4].[BrandID] = [t0].[BrandID]
) AS [value]
FROM [Brand] AS [t0]
LEFT OUTER JOIN ([Source] AS [t1]
INNER JOIN [BrandSource] AS [t2] ON [t1].[SourceID] = [t2].[SourceID]) ON [t2].[BrandID] = [t0].[BrandID]
And here's some test data for those following along at home:
create table Brand (
BrandID int,
Name varchar(50),
)
create table BrandSource (
BrandID int,
SourceID int
)
create table Source (
SourceID int,
SourceName varchar(50),
[Image] varchar(50)
)
insert into Brand select 1, 'Brand1'
insert into Brand select 2, 'Brand2'
insert into Brand select 3, 'Brand3'
insert into Source select 1, 'Source1', 'src1.gif'
insert into Source select 2, 'Source2', 'src2.jpg'
insert into Source select 3, 'Source3', 'src3.bmp'
insert into Source select 4, 'Source4', 'src4.png'
insert into Source select 5, 'Source5', 'src5.raw'
insert into BrandSource select 1, 1
insert into BrandSource select 1, 2
insert into BrandSource select 1, 3
insert into BrandSource select 2, 2
insert into BrandSource select 2, 4
select * from Brand
select * from BrandSource
select * from Source
Notice that you get an empty list of sources for brand #3 this way, which is what I assume you'd want. Your original query INNER JOINed Brand#3 away.
Finally, here's an example of how you'd use your query result:
foreach (var result in results) {
string chk = (result.Brand.Active ? " checked='checked'" : "");
var buf = new StringBuilder();
buf.Append("<tr>");
buf.AppendFormat("<td><input type='checkbox'{0}></td>", chk);
buf.AppendFormat("<td width='1%'><img width='50px' src='{0}'></img></td>", result.Brand.Image);
buf.AppendFormat("<td>{0}</td>", result.Brand.Name);
buf.Append("<td>");
foreach(var src in result.Sources) {
buf.AppendFormat("<img src='{0}'></img>", src.Image);
}
buf.Append("</td>");
buf.Append("</tr>");
resultSpan.InnerHtml = buf.ToString();
}
Sort the LINQ query by BrandID
then use a variable to keep track if it is a new brand.
int lastBrandID = 0;
string closeHtml = "";
foreach (var result in join)
{
if(result.Brand.BrandID != lastBrandID)
{
resultSpan.InnerHtml += closeHtml;
bool a = result.Brand.Active;
string chk = string.Empty;
if (a == true)
chk = "checked='checked'";
else
chk = "";
resultSpan.InnerHtml += "<tr><td><input type='checkbox' " + chk + "></td><td width='1%'><img width='50px' src='" + result.Brand.Image + "'</img></td>" +
"<td>" + result.Brand.Name + "</td><td width='60%'>" + result.c + "</td><td>";
closeHtml = "</td><td>" + result.Brand.DateCreated + "</td><td>" + result.Brand.DateModified + "</td></tr>";
lastBrandID = result.Brand.BrandID;
}
resultSpan.InnerHtml += "<img src='"+result.source+"'></img>";
}
resultSpan.InnerHtml += closeHtml;
On a side note, use a StringBuilder instead of concatenating your strings.
http://msdn.microsoft.com/en-us/library/2839d5h5%28v=VS.100%29.aspx
You can use GroupBy for this (or group .. by .. into in a query) on your original query thus:
var groups = join.GroupBy(b => b.Brand);
foreach (var group in groups)
{
var brand = group.Key;
foreach (var row in group)
{
// you get the idea
}
}