This is strange.
I am moving a stored proc to a service. The TSQL unions multiple selects. To replicate this I created multiple queries resulting in a common new concrete type. Then I issue a return result.ToString(); and the resulting SQL selects have varying numbers of columns specified thus causing an MSSQL Msg 205...
using (var db = GetDb())
{
var fundInv = from f in db.funds
select
new Investments
{
Company = f.company,
FullName = f.fullname,
Admin = f.admin,
Fund = f.fund1,
FundCode = f.fundcode,
Source = STR_FUNDS,
IsPortfolio = false,
IsActive = f.active,
Strategy = f.strategy,
SubStrategy = f.substrategy,
AltStrategy = f.altstrategy,
AltSubStrategy = f.altsubstrategy,
Region = f.region,
AltRegion = f.altregion,
UseAlternate = f.usealt,
ClassesAllowed = f.classallowed
};
var stocksInv = from s in db.stocks
where !fundInv.Select(f => f.Company).Contains(s.vehcode) select
new Investments
{
Company = s.company,
FullName = s.issuer,
Admin = STR_PRS,
Fund = s.shortname,
FundCode = s.vehcode,
Source = STR_STOCK,
IsPortfolio = false,
IsActive = (s.inactive == null),
Strategy = s.style,
SubStrategy = s.substyle,
AltStrategy = s.altstyle,
AltSubStrategy = s.altsubsty,
Region = s.geography,
AltRegion = s.altgeo,
UseAlternate = s.usealt,
ClassesAllowed = STR_GENERIC
};
var bondsInv = from oi in db.bonds
where !fundInv.Select(f => f.Company).Contains(oi.vehcode)
select
new Investments
{
Company = string.Empty,
FullName = oi.issue,
Admin = STR_PRS1,
Fund = oi.issue,
FundCode = oi.vehcode,
Source = STR_BONDS,
IsPortfolio = false,
IsActive = oi.closed,
Strategy = STR_OTH,
SubStrategy = STR_OTH,
AltStrategy = STR_OTH,
AltSubStrategy = STR_OTH,
Region = STR_OTH,
AltRegion = STR_OTH,
UseAlternate = false,
ClassesAllowed = STR_GENERIC
};
return (fundInv.Concat(stocksInv).Concat(bondsInv)).ToList();
}
The code above results in a complex select statement where each "table" above has different column count. (see SQL below) I've been trying a few things but no change yet. Ideas are welcome.
SELECT [t6].[company] AS [Company],
[t6].[fullname] AS [FullName],
[t6].[admin] AS [Admin],
[t6].[fund] AS [Fund],
[t6].[fundcode] AS [FundCode],
[t6].[value] AS [Source],
[t6].[value2] AS [IsPortfolio],
[t6].[active] AS [IsActive],
[t6].[strategy] AS [Strategy],
[t6].[substrategy] AS [SubStrategy],
[t6].[altstrategy] AS [AltStrategy],
[t6].[altsubstrategy] AS [AltSubStrategy],
[t6].[region] AS [Region],
[t6].[altregion] AS [AltRegion],
[t6].[usealt] AS [UseAlternate],
[t6].[classallowed] AS [ClassesAllowed]
FROM (
SELECT [t3].[company],
[t3].[fullname],
[t3].[admin],
[t3].[fund],
[t3].[fundcode],
[t3].[value],
[t3].[value2],
[t3].[active],
[t3].[strategy],
[t3].[substrategy],
[t3].[altstrategy],
[t3].[altsubstrategy],
[t3].[region],
[t3].[altregion],
[t3].[usealt],
[t3].[classallowed]
FROM (
SELECT [t0].[company],
[t0].[fullname],
[t0].[admin],
[t0].[fund],
[t0].[fundcode],
#p0 AS [value],
[t0].[active],
[t0].[strategy],
[t0].[substrategy],
[t0].[altstrategy],
[t0].[altsubstrategy],
[t0].[region],
[t0].[altregion],
[t0].[usealt],
[t0].[classallowed]
FROM [zInvest].[funds] AS [t0]
UNION ALL
SELECT [t1].[company],
[t1].[issuer],
#p6 AS [value],
[t1].[shortname],
[t1].[vehcode],
#p7 AS [value2],
#p8 AS [value3],
(CASE
WHEN [t1].[inactive] IS NULL THEN 1
ELSE 0
END) AS [value5],
[t1].[style],
[t1].[substyle],
[t1].[altstyle],
[t1].[altsubsty],
[t1].[geography],
[t1].[altgeo],
[t1].[usealt],
#p10 AS [value6]
FROM [zBank].[stocks] AS [t1]
WHERE (NOT (EXISTS(
SELECT NULL AS [EMPTY]
FROM [zInvest].[funds] AS [t2]
WHERE [t2].[company] = [t1].[vehcode]
))) AND ([t1].[vehcode] <> #p2) AND (SUBSTRING([t1].[vehcode], #p3 + 1, #p4) <> #p5)
) AS [t3]
UNION ALL
SELECT #p11 AS [value],
[t4].[issue],
#p12 AS [value2],
[t4].[vehcode],
#p13 AS [value3],
#p14 AS [value4],
[t4].[closed],
#p16 AS [value6],
#p17 AS [value7]
FROM [zMut].[bonds] AS [t4]
WHERE NOT (EXISTS(
SELECT NULL AS [EMPTY]
FROM [zInvest].[funds] AS [t5]
WHERE [t5].[company] = [t4].[vehcode]
))
) AS [t6]
Think it is a bug in LINQ to SQL. You can find it here:
http://connect.microsoft.com/VisualStudio/feedback/details/355734/linq-to-sql-produces-incorrect-tsql-when-using-union-or-concat
Hope the workaround given there works for you.
Related
The SQL query I'm trying to convert is:
select p.PhoneNumber_Id, p.State, p.Created
from PhoneNumberServiceItems p
join PhoneNumbers on p.PhoneNumber_Id = PhoneNumbers.Id
inner join (
select PhoneNumber_Id, max(Created) as MaxDate
from PhoneNumberServiceItems
group by PhoneNumber_Id
) tm on p.PhoneNumber_Id = tm.PhoneNumber_Id and p.Created = tm.MaxDate
where PhoneNumbers.NumberRangeId = {Id}
And the LINQ code I've ended up with is below, however this isn't working:
var res =
from serviceItems in _db.PhoneNumberServiceItems
join nums in _db.PhoneNumbers on serviceItems.PhoneNumber_Id equals nums.Id
where nums.NumberRangeId == id
join serviceGroup in (from ps in _db.PhoneNumberServiceItems
group ps by ps.PhoneNumber_Id into numGroup
//join tm in _db.PhoneNumbers on psg.FirstOrDefault().PhoneNumber_Id equals tm.Id
select new
{
NumId = numGroup.FirstOrDefault().PhoneNumber_Id,
MaxDate = numGroup.Max(i => i.Created)
}) on new { PNId = serviceItems.PhoneNumber_Id, serviceCreated = serviceItems.Created } equals new { PNId = serviceGroup.NumId, serviceCreated = serviceGroup.MaxDate }
select new
{
State = serviceItems.State,
NumId = serviceGroup.NumId,
Created = serviceGroup.MaxDate
};
I'm aware my LINQ is wrong, but I can't put my finger on what it is I'm doing differently. Any help would be appreciated.
Edit: This is the compiled SQL generated from the LINQ
SELECT
[Extent1].[State] AS [State],
[Project4].[C1] AS [C1],
[Project4].[C2] AS [C2]
FROM [dbo].[PhoneNumberServiceItems] AS [Extent1]
INNER JOIN [dbo].[PhoneNumbers] AS [Extent2] ON [Extent1].[PhoneNumber_Id] = [Extent2].[Id]
INNER JOIN (SELECT
[Project3].[C1] AS [C1],
(SELECT
MAX([Extent5].[Created]) AS [A1]
FROM [dbo].[PhoneNumberServiceItems] AS [Extent5]
WHERE [Project3].[PhoneNumber_Id] = [Extent5].[PhoneNumber_Id]) AS [C2]
FROM ( SELECT
[Distinct1].[PhoneNumber_Id] AS [PhoneNumber_Id],
(SELECT TOP (1)
[Extent4].[PhoneNumber_Id] AS [PhoneNumber_Id]
FROM [dbo].[PhoneNumberServiceItems] AS [Extent4]
WHERE [Distinct1].[PhoneNumber_Id] = [Extent4].[PhoneNumber_Id]) AS [C1]
FROM ( SELECT DISTINCT
[Extent3].[PhoneNumber_Id] AS [PhoneNumber_Id]
FROM [dbo].[PhoneNumberServiceItems] AS [Extent3]
) AS [Distinct1]
) AS [Project3] ) AS [Project4] ON ([Extent1].[PhoneNumber_Id] = [Project4].[C1]) AND ([Extent1].[Created] = [Project4].[C2])
WHERE [Extent2].[NumberRangeId] = {id}
This is linq equivalent of your query.
var res = from s in PhoneNumberServiceItems
join p in PhoneNumbers on s.PhoneNumber_Id equals p.Id
join tm in ( from p1 in PhoneNumberServiceItems
group p1 by p1.PhoneNumber_Id into p_g
select new {PhoneNumber_Id = p_g.Key,MaxDate = p_g.Max(i=> i.Created) } )
on new {Created = s.Created, PhoneNumber_Id = s.PhoneNumber_Id}
equals new { Created = tm.MaxDate, PhoneNumber_Id = tm.PhoneNumber_Id}
where p.NumberRangeId == {Id}
select new
{
s.PhoneNumber_Id,
s.State,
s.Created
};
Try following which is much simpler :
var res = (from nums in _db.PhoneNumbers.Where(x => NumberRangeId == id)
join serviceItems in _db.PhoneNumberServiceItems on nums.PhoneNumber_Id equals serviceItems.Id
select new {serviceItems = serviceItems, nums = nums})
.OrderByDescending(x => x.serviceItems.Created)
.GroupBy(x => x.nums.PhoneNumber_Id)
.Select(x => x.First())
.Select(x => new {Id = x.nums.PhoneNumber_Id, state = x.serviceItems.State, maxDate = x.serviceItems.Created})
.ToList();
var recentPhoneNos= from psi in _db.PhoneNumberServiceItems
group psi by psi .PhoneNumber_Id into psiTemp
select new {
PhoneNumber_Id = psiTemp.Key,
MaxDate = psiTemp.Max(i=> i.Created)
};
var res=from serviceItems in _db.PhoneNumberServiceItems
join nums in _db.PhoneNumbers on serviceItems.PhoneNumber_Id equals nums.Id
join serviceGroup in recentPhoneNos on nums.Id equals serviceGroup .PhoneNumber_Id
where nums.NumberRangeId == id && serviceGroup.MaxDate
select new {
State = serviceItems.State,
NumId = serviceGroup.NumId,
Created = serviceGroup.MaxDate
} ;
Trying to use LINQ to join three datatables table1, table2, table3. Table1 and table2 joined on 2 condition and table 1 and table 3 joined on 1 condition. Following is my code. But I am getting an exception saying that
"Unable to cast object of type 'System.DBNull' to type 'System.String'."
Below is my code:
var result = from cust in tblCust.AsEnumerable()
join mat in tblMat.AsEnumerable()
new { coil_id = (string)cust["coil_id"], order_id = (string)cust["order_id"] }
equals
new { coil_id = (string)mat["PIECE_ID"], order_id = (string)mat["PRODUCTION_ORDER_ID"] }
join parts in tblParts.AsEnumerable() on (string)mat["PIECE_ID"] equals (string)parts["ProdCoilNo"]
select new
{
coil_id = mat["PIECE_ID"],
order_id = mat["PRODUCTION_ORDER_ID"],
part = parts["PartNumber"],
gauge = mat["THICKNESS"],
width = mat["WIDTH"],
weight = mat["WEIGHT"],
code = mat["MATERIAL_BLOCK_STATE"],
requestor_comment = cust["requestor_comment"],
requestor = cust["requestor"],
updated_by_comment = cust["updated_by_comment"],
updated_by_user = cust["updated_by_user"]
};
I an getting an exception near (string)parts["ProdCoilNo"]
Use the coalesce operator for the field containing null to replace with empty string
Like this:
coil_id = mat["PIECE_ID"] ?? String.Empty,
Use the coalesce operator
var result = from cust in tblCust.AsEnumerable()
join mat in tblMat.AsEnumerable()
new { coil_id = (string)cust["coil_id"], order_id = (string)cust["order_id"] }
equals
new { coil_id = (string)mat["PIECE_ID"], order_id = (string)mat["PRODUCTION_ORDER_ID"] }
join parts in tblParts.AsEnumerable() on (string)mat["PIECE_ID"] equals (string)parts["ProdCoilNo"]
select new
{
coil_id = mat["PIECE_ID"]?? String.Empty,
order_id = mat["PRODUCTION_ORDER_ID"]?? String.Empty,
part = parts["PartNumber"]?? String.Empty,
gauge = mat["THICKNESS"]?? String.Empty,
width = mat["WIDTH"]?? String.Empty,
weight = mat["WEIGHT"]?? String.Empty,
code = mat["MATERIAL_BLOCK_STATE"]?? String.Empty,
requestor_comment = cust["requestor_comment"]?? String.Empty,
requestor = cust["requestor"]?? String.Empty,
updated_by_comment = cust["updated_by_comment"]?? String.Empty,
updated_by_user = cust["updated_by_user"]?? String.Empty
};
I am trying converting sql query into LINQ but after write query unable to fetch record from resultset
SELECT T.ServiceOrderNo,T.STATUS, T.SubStatus,T.orderVersion,T.OrderDate
,#pid, T.EventID, 'FOI'
FROM #temp1 T
LEFT JOIN Tbl_Service_Order_Progress O ON T.ServiceOrderNo DATABASE_DEFAULT = O.ServiceOrderNo
AND O.PARENTID = #pid
AND O.ServiceOrderType = 'FOI'
WHERE O.ServiceOrderNo IS NULL
Above Query following I'm trying in LINQ
var lstInsertFOI = (from i in lstFOI
join j in lstSOP on i.fulfilmentOrderItemIdentifier equals j.ServiceOrderNo into res
from subRight in res.DefaultIfEmpty()
where subRight.ParentId == parentId && subRight.ServiceOrderNo == null && subRight.ServiceOrderType.Equals("FOI")
select new
{
ServiceOrderNo = subRight.ServiceOrderNo == null ? i.fulfilmentOrderItemIdentifier : subRight.ServiceOrderNo,
EventStatus = i.status,
EventSubStatus = i.subStatus,
OrderVersion = i.orderVersion,
EVENTRECEIVEDDATE = i.orderDate,
ParentId = parentId,
EventID = i.eventID,
ServiceOrderType = "FOI",
}).ToList();
above linq query does not fetch expected result, which should return number of records from lstFOI list, but returns no record. Is the linq query correct?
Let start with SQL query.
LEFT JOIN Tbl_Service_Order_Progress O
ON T.ServiceOrderNo = O.ServiceOrderNo
AND O.PARENTID = #pid AND O.ServiceOrderType = 'FOI'
is equivalent to
LEFT JOIN (SELECT * FROM Tbl_Service_Order_Progress
WHERE PARENTID = #pid AND ServiceOrderType = 'FOI') O
ON T.ServiceOrderNo = O.ServiceOrderNo
then
WHERE O.ServiceOrderNo IS NULL
means that the query is actually using anti-join, i.e. include all the records from the left side that do not have a matching records from the right side.
With all that in mind, the equivalent LINQ query should be like this:
var lstInsertFOI = (
from i in lstFOI
join j in lstSOP
.Where(e => e.ParentId == parentId && subRight.ServiceOrderType == "FOI")
on i.fulfilmentOrderItemIdentifier equals j.ServiceOrderNo into res
where !res.Any()
select new
{
ServiceOrderNo = i.fulfilmentOrderItemIdentifier,
EventStatus = i.status,
EventSubStatus = i.subStatus,
OrderVersion = i.orderVersion,
EVENTRECEIVEDDATE = i.orderDate,
ParentId = parentId,
EventID = i.eventID,
ServiceOrderType = "FOI",
}).ToList();
Doing some stuff linq left join query but facing some problem. Not able to get proper result following sql query need to convert into linq
INSERT INTO tbl_service_order_attributes_versioning(ServiceOrderNo, AttributeId, AttributeValue, parentid, AttributeType, Dt_Stamp, VERSION)
SELECT
T.ServiceOrderNo, T.COIID, T.COI_Identifier,
#pid, 'MBM', getDate(), #ORDERVERSION
FROM
#temp1 T
LEFT JOIN
tbl_service_order_attributes_versioning O WITH(NOLOCK)
ON T.ServiceOrderNo = O.ServiceOrderNo COLLATE database_default
AND T.COIID = O.AttributeID
AND O.PARENTID = #pid
WHERE
O.ServiceOrderNo IS NULL
I have converted this query into a Linq query:
var soiAttr = (from s in ctxParser.TBL_SERVICE_ORDER_ATTRIBUTES_VERSIONING
where s.ParentId == parentId
select s).ToList();
var resultJoinCOI = (from soaI in soiAttr
join iFoi in listFOI on soaI.ServiceOrderNo equals iFoi.fulfilmentOrderItemIdentifier
where iFoi.coiId == soaI.AttributeId &&
iFoi.parentId == parentId &&
soaI.ServiceOrderNo == null
select iFoi).ToList();
if (resultJoinCOI.Count > 0)
{
var listToInsert = (from item in resultJoinCOI
select new TBL_SERVICE_ORDER_ATTRIBUTES_VERSIONING
{
ServiceOrderNo = item.fulfilmentOrderItemIdentifier,
AttributeId = item.coiId,
AttributeValue = item.coiIdentifier,
ParentId = parentId,
AttributeType = "MBM",
DT_Stamp = DateTime.Now,
VERSION = orderVersion
});
ctxParser.TBL_SERVICE_ORDER_ATTRIBUTES_VERSIONING.AddRange(listToInsert);
ctxParser.SaveChanges();
}
The code is executed but result are not correct.
You need to use DefaultIfEmpty (https://msdn.microsoft.com/en-us/library/bb360179.aspx). Here's a reading from MSDN: https://msdn.microsoft.com/en-us/library/bb397895.aspx
In your case it would be something like:
var resultJoinCOI = (
from iFoi in listFOI
join soaI in soiAttr on iFoi.fulfilmentOrderItemIdentifier equals soaI.ServiceOrderNo into res
from subIFoi in res.DefaultIfEmpty()
where iFoi.coiId == soaI.AttributeId && iFoi.parentId == parentId && subIFoi == null
select iFoi).ToList();
Following code that execute successfully. and getting right result.
var soiAttr = (from s in ctxParser.TBL_SERVICE_ORDER_ATTRIBUTES_VERSIONING
where s.ParentId == parentId
select s).ToList();
var resultJoinCOI = (from iFoi in listFOI
join soaI in soiAttr on
new
{
ServiceOrderNo = iFoi.fulfilmentOrderItemIdentifier,
AttributeId = iFoi.coiId
}
equals new
{
ServiceOrderNo = soaI.ServiceOrderNo,
AttributeId = soaI.AttributeId
}
into res
from subFoi in res.DefaultIfEmpty()
select new
{
fulfilmentOrderItemIdentifier = iFoi.fulfilmentOrderItemIdentifier,
coiId = iFoi.coiId,
coiIdentifier = iFoi.coiIdentifier,
AttributeId = subFoi == null ? 0 : subFoi.AttributeId,
ParentId = subFoi == null ? parentId : subFoi.ParentId,
ServiceOrderNo = subFoi == null ? string.Empty: subFoi.ServiceOrderNo
});
if (resultJoinCOI != null)
{
if (resultJoinCOI.Count() > 0)
{
var listToInsert = (from item in resultJoinCOI
select new TBL_SERVICE_ORDER_ATTRIBUTES_VERSIONING
{
ServiceOrderNo = item.fulfilmentOrderItemIdentifier,
AttributeId = item.coiId,
AttributeValue = item.coiIdentifier,
ParentId = parentId,
AttributeType = "MBM",
DT_Stamp = DateTime.Now,
VERSION = orderVersion
});
ctxParser.TBL_SERVICE_ORDER_ATTRIBUTES_VERSIONING.AddRange(listToInsert);
ctxParser.SaveChanges();
}
}
In this way we can implement left join in linq. as per above SQL Query(see above sql statement).
i having problem in sql by using ExecuteStoreQuery Please see the example at below
My coding
private void ChildMenuItem()
{
using (LEWREDBEntities ctx = new LEWREDBEntities())
{
string result = #"
WITH ctLevel
AS
(
SELECT
C_TASK_ID AS Child
,P_Task_ID AS Parent
,common_task. TASK_SEQ AS taskSeq
,1 AS [Level]
,CAST( TASK_SEQ AS VARCHAR(MAX)) AS [taskOrder]
,CAST (Replicate('', 1) + common_task.TASK_NAME AS VARCHAR(MAX)) AS [Task_Name]
FROM
[COMMON.TASK_REL] as common_task_rel,
[COMMON.TASK] as common_task
WHERE
common_task_rel.C_TASK_ID = common_task.TASK_ID
and common_task.[TASK_TYPE] = 'F' AND common_task.[MODULE_CODE] = 'PRODE' AND common_task.[STATUS] <> 'D'
and C_TASK_ID =357
UNION ALL
SELECT
C_TASK_ID AS Child
,P_Task_ID AS Parent
,common_task. TASK_SEQ AS taskSeq
,[Level] + 1 AS [Level]
,[taskOrder] + '.' + CAST(TASK_SEQ AS VARCHAR(MAX)) AS [taskOrder]
,CAST (Replicate('', [Level] + 1) + common_task.TASK_NAME AS VARCHAR(MAX)) AS [Task_Name]
FROM
[COMMON.TASK_REL]as common_task_rel
INNER JOIN
ctLevel
ON
( P_Task_ID = Child ) ,
[COMMON.TASK] as common_task
WHERE
common_task_rel.C_TASK_ID = common_task.TASK_ID
and common_task.[TASK_TYPE] = 'F' AND common_task.[MODULE_CODE] = 'PRODE' AND common_task.[STATUS] <> 'D'
)
SELECT
common_task.Task_Name,
common_task_url.TASK_URL,
ctLevel.CHILD
FROM
ctLevel,
[COMMON.ACL] as common_acl,
[COMMON.STAFF_ROLE] as common_staff_role,
[COMMON.TASK_URL] as common_task_url,
[COMMON.TASK] as common_task,
[COMMON.STAFF_MODULE] as common_staff_module,
[common.module] as common_module
where ctLevel.Level =3
and ctLevel.Child = common_acl.TASK_ID
and common_acl.READ_ACCESS ='Y'
and common_acl.STATUS <>'D'
and common_acl.ROLE_ID = common_staff_role.ROLE_ID
and common_staff_role.STATUS <>'D'
and common_staff_role.STAFF_ID ='user'
and common_staff_role.STAFF_ID = common_staff_module.STAFF_ID
and common_staff_module.MODULE_CODE =common_module.MODULE_CODE
and common_staff_module.STATUS<>'D'
and common_staff_module.MODULE_CODE = common_module.MODULE_CODE
and common_module.STATUS <>'D' and common_module.MODULE_CODE ='PRODE'
and common_acl.TASK_ID = common_task.TASK_ID
and common_task.STATUS <>'D'
and common_task.TASK_TYPE ='F'
and common_task.TASK_POSITION ='S'
and common_task.TASK_ID = common_task_url.TASK_ID
and common_task_url.DEFAULT_URL ='Y'
and common_task_url.STATUS<>'D'
Group By
[taskOrder],common_task.Task_Name, TASK_URL,ctLevel.CHILD
order by [taskOrder],common_task.Task_Name, TASK_URL,ctLevel.CHILD";
var query = ctx.ExecuteStoreQuery<dlcGvTask>
(result);
foreach (dlcGvTask gvTask in query.ToList())
{
MenuItem navigation = new MenuItem(gvTask.TASK_NAME, gvTask.Child.ToString(), "","");
MenuChild.Items.Add(navigation);
}
//Here????
var id = (from table in query
select table.Child).Take(1);
;
}
}
Now i got a question.How can i select the top 1 of the Record?
In your code
//Here????
var id = (from table in query
select table.Child).Take(1);
Try
var id = query.First();
//Or
var id = query.Take(1);
Try to do something like this:-
Select Top 1 ..... ;
OR
..... Where ROW_NUMBER() = 1;