String concatenation in join clause - c#

I have been having some issue with adding some string concatenation in my LINQ JOIN condition and its translation in Oracle sql query. This used to work fine on our legacy solution that was using EF.
Let's take the following example:
var query = (from sub in connection.InvoiceSubStatuses
join lab in connection.Litteral
on "STN_ASP_PIE_STATUT_EXTERNE[" + sub.StatusCode + "]" + "{" + vendorId + "}" equals lab.Code
where sub.IsFlaggedDelete == 0
select new InvoiceSubStatusDTO
{
Description = lab.Libelle,
StatusCode = sub.StatusCode,
Id = sub.Id,
Culture = lab.Culture,
StatusType = sub.StatusType
});
This is interpreted as the following sql code:
SELECT "l".LIBELLE "Description", "s".CODE_STATUSFAC "StatusCode", "s".SYS_ID "Id", "l".CULTURE "Culture", "s".TYPE_STATUSFAC "StatusType"
FROM STATUSFAC "s"
INNER JOIN LITTERAUX "l" ON N'STN_ASP_PIE_STATUT_EXTERNE[' || COALESCE("s".CODE_STATUSFAC, N'') || N']' || N'{' || TO_NCHAR(:p__vendorId_0) || N'}' = "l".CODE
WHERE ("s".DIGITAL_LETTER = 1) AND ("s".SYS_FLAG_DEL = 0)
This causes an error , as Oracle doesn't allow 'N' text literal inside COALESCE ( COALESCE("s".CODE_STATUSFAC, N'')). If I manually change it to COALESCE("s".CODE_STATUSFAC, ''), the query works fine, but I don't know how to resolve this from Linq.
Has anyone encountered this issue and found a workaround?Thanks

So the issue was coming from the fact that the column in the DB in non-nullable, so when trying to do a string concatenation, the Oracle provider adds the COALESCE . So in order to bypass this , I added the attribute [Required] on the column StatusCode .

Related

Combining Two Different DbContexts (LINQ) from Separate Databases

I am getting the error:
The specified LINQ expression contains references to queries that are associated with different contexts.
because I'm trying to combine two different DbContexts, each from separate databases.
I was trying to convert this SQL:
SELECT orderformdump.itemno,basedescription,info,upc,CAST(UNITPRICE AS DECIMAL(18,2)),caseqty, sum(qty) AS userquantity
FROM [DataWarehouse].[dbo].[ORDERFORMDUMP]
LEFT JOIN PPPLTD.dbo.ICPRICP ON replace([DataWarehouse].[dbo].[ORDERFORMDUMP].[ITEMNO],'-','') = ICPRICP.ITEMNO
LEFT JOIN PPPLTD.dbo.WEBITEMINFO ON ORDERFORMDUMP.ITEMNO = WEBITEMINFO.ITEMNO
LEFT JOIN pppltd.dbo.weboeordh ON [user] = #username
LEFT JOIN pppltd.dbo.weboeordd ON pppltd.dbo.WEBOEORDD.ITEMNO = REPLACE(datawarehouse.dbo.ORDERFORMDUMP.ITEMNO,'-','') and weboeordd.ORDUNIQ = weboeordh.orduniq
Left JOIN pppltd.dbo.weboeordsubmit ON weboeordsubmit.orduniq = weboeordd.ORDUNIQ and weboeordd.ORDUNIQ != weboeordsubmit.orduniq
LEFT JOIN PPPLTD.dbo.WEBLOGINACCESS ON WEBLOGINACCESS.[USER] = #username
LEFT JOIN PPPLTD.dbo.ARCUS ON ARCUS.IDCUST = WEBLOGINACCESS.CUSTID
where (allowinbc = 'Yes' or allowinab = 'Yes')
AND [PRICELIST] = ARCUS.PRICLIST
and [CURRENCY] = 'CDN' and DPRICETYPE = 1
and (itemgroup like '%' + #search + '%' or itemtype like '%' + #search + '%' or itembrand like '%' + #search + '%'
or subcat like '%' + #search + '%' or orderformdump.description like '%' + #search + '%' or basedescription like '%'+ #search + '%'
or orderformdump.ITEMNO like '%'+#search+'%' or UPC like '%'+#search+'%' or (select top 1 1 from pppltd.dbo.ICITEMO where OPTFIELD like 'UPC%' and VALUE like '%'+#search+'%'
and ITEMNO = DataWarehouse.dbo.ORDERFORMDUMP.itemno) is not null)
group by ORDERFORMDUMP.ITEMNO,BASEDESCRIPTION,info,UPC,CAST(UNITPRICE AS DECIMAL(18,2)),caseqty
order by basedescription
to LINQ:
var qty = db.WebOEOrdD.Sum(d => d.QTY);
var unitPrice = db.IcPricP.Select(p => decimal.Round(p.UNITPRICE, 2));
var query = from item in dbData.OrderFormDump
join icp in db.IcPricP on item.ITEMNO.Replace("-", "") equals icp.ITEMNO
join itemInfo in db.WebItemInfo on item.ITEMNO equals itemInfo.ITEMNO
join weboeordh in db.WebOEOrdH on username equals weboeordh.USER
join weboeordd in db.WebOEOrdD on new { itemno = item.ITEMNO.Replace("-", ""), orduniq = weboeordh.ORDUNIQ } equals new { itemno = weboeordd.ITEMNO, orduniq = weboeordd.ORDUNIQ }
join weboeordsubmit in db.WebOEOrdSubmit on weboeordd.ORDUNIQ equals weboeordsubmit.ORDUNIQ where weboeordsubmit.ORDUNIQ != weboeordd.ORDUNIQ
join webloginaccess in db.WebLoginAccess on username equals webloginaccess.USER
join arcus in db.Arcus on webloginaccess.CUSTID equals arcus.IDCUST
where (item.ALLOWINBC == "Yes" && item.ALLOWINAB == "Yes")
&& icp.PRICELIST == arcus.PRICLIST
&& icp.CURRENCY == "CDN" && icp.DPRICETYPE == 1
&& (item.BASEDESCRIPTION.Contains(searchword) || item.DESCRIPTION.Contains(searchword) || item.CATEGORY.Contains(searchword) || item.FOODACCSPEC.Contains(searchword) || item.ITEMBRAND.Contains(searchword) || item.ITEMGROUP.Contains(searchword) || item.ITEMNO.Contains(searchword) || item.ITEMSUBTYPE.Contains(searchword) || item.ITEMTYPE.Contains(searchword) || itemInfo.INFO.Contains(searchword) || item.UPC.Contains(searchword) || item.UPC.Substring(2, 10).Contains(searchword))
orderby item.BASEDESCRIPTION
group item by new { item.ITEMNO, item.BASEDESCRIPTION, itemInfo.INFO, item.UPC, unitPrice, item.CASEQTY, qty } into items
select new { items.Key.ITEMNO, items.Key.BASEDESCRIPTION, items.Key.INFO, items.Key.UPC, unitPrice, items.Key.CASEQTY, qty };
Am I converting it correctly? Do I have to create two separate queries and combine them? Lastly, can I combine two different databases into one dbContext? If so, how do I do this?
Thank you.
UPDATE
I tried adding tables from another database into my main dbContext and I'm getting this error:
The entity type ORDERFORMDUMP is not part of the model for the current context.
UPDATE #2
What I did to solve my problem doesn't really answer this question, however it is a good workaround.
What I did was I took the only table in my query that was part of a different DbContext and another database (ORDERFORMDUMP), and I copied that table to the main database in SQL Server. As a result, I was able to add that table to my main DbContext.
There are a couple ways of accomplishing this.
I would recommending creating a view of your query, then bind it to a new linq object, and then you can query off of that. Trying to write your query fully in linq is possible, but it would just get nasty, given you are working with multiple data contexts.
You are going to have to have two different queries, materialize the query results, then do whatever operations you want to do on them in memory.
What I did to solve my problem doesn't really answer this question, however it is a good workaround.
What I did was I took the only table in my query that was part of a different DbContext and another database (ORDERFORMDUMP), and I copied that table to the main database in SQL Server. As a result, I was able to add that table to my main DbContext.

Using SQL instead of LINQ in Telerik Open Access

I'm using Telerik Open Access. I have two separate projects that have Open Access data and then a third project that has the bulk of my code. I've been working on a way to convert a simple (at least I thought it was) SQL query to LINQ so that I can get the data I need. I have not been successful. I've had to break a single LINQ query into separate queries, because of the need for the Trim() function (I think). This has led to a lengthy piece of code and I'm still not getting the same results as my SQL query.
So my question is, is there anyway to use SQL instead of LINQ to access the data in the Open Access projects? If so, can you show me the syntax to do that for my query?
If it is not possible to use SQL, can you show me show me the proper way to convert my SQL query into LINQ so that I get the same results?
Thank you.
My SQL query is
SELECT DISTINCT us2.ccustno, us2.dispname, us2.csiteno, so.s1_name
FROM [DALubeDeacom].[dbo].[dmbill] bi
INNER JOIN [DALubeDeacom].[dbo].[dmso1] so
ON bi.bi_s1id = so.s1_id
INNER JOIN [DALubeNew].[dbo].[usersecurity] us2
ON so.s1_name = us2.cparentno
WHERE
us2.ctype = 'JOBSITE'
AND us2.csiteno is not null
AND us2.csiteno != ''
AND bi.bi_smid = '22'
ORDER BY us2.csiteno
My LINQ query is
public List<DataModelSample> GetLocationsBySalesNo(string salesNo)
{
int iSalesNo = int.Parse(salesNo.Trim());
try
{
var dmso = (
from so in deacom.Dmso1
join qt in deacom.Dmbills
on so.S1_id equals qt.Bi_s1id
where qt.Bi_smid == iSalesNo
select new Dmso1
{
S1_id = so.S1_id
, S1_name = so.S1_name.Trim()
}
);
var usec = (
from us in dbContext.Usersecurities
where us.Cparentno != null && us.Cparentno.Trim() != "" && us.Ctype.Trim() == "JOBSITE" && us.Csiteno.Trim() != ""
select new Usersecurity
{
Ccustno = us.Ccustno.Trim(),
Csiteno = us.Csiteno.Trim(),
Dispname = us.Dispname.Trim(),
Cparentno = us.Cparentno.Trim()
}
);
var customers =
(
from us in usec
join so in dmso
on us.Cparentno equals so.S1_name
select us
);
customers = customers.GroupBy(x => x.Csiteno).Select(x => x.First());
List<DataModelSample> listLocations =
(
from c in customers
select new DataModelSample
{
customerID = c.Ccustno
,
origLocationName = c.Csiteno + " " + c.Dispname
,
origLocationID = c.Csiteno
}
).OrderBy(x => x.origLocationID).ToList();
return listLocations.ToList();
}
catch (Exception ex)
{
throw ex;
}
} // GetLocationsBySalesNo(userInfo.csalesno)
Edit 1 - 2-19-16
Tried a suggestion by ViktorZ. His query was similar to the one I first tried. It returned the error "Identifier 'Ctype' is not a parameter or variable or field of 'DALube_DeacomModel.Dmbill'. If 'Ctype' is a property please add the FieldAlias or Storage attribute to it or declare it as a field's alias." From an online search, it looked like this was do to "extended fields". I don't seemed to be using such fields. The only way I could get around this error was to break it into the smaller LINQ queries in my original question, which didn't produce the right results. Any suggestions?
Here's the code:
var query = (from bill in deacom.Dmbills
join so in deacom.Dmso1 on bill.Bi_s1id equals so.S1_id
join us in dbContext.Usersecurities on so.S1_name equals us.Cparentno
where us.Ctype == "JOBSITE"
&& us.Csiteno != null
&& us.Csiteno != string.Empty
&& bill.Bi_smid == iSalesNo
select new
{
ccustno = us.Ccustno.Trim(),
dispname = us.Dispname.Trim(),
csiteno = us.Csiteno.Trim(),
s1_name = so.S1_name.Trim()
}).Distinct();
One very crude approximation of your SQL query is:
var query = (from bill in deacom.Bills
join so in deacom.LubeDeacom on bill.bi_s1id equals so.s1_id
join us in deacom.UserSecurity on so.s1_name equals us.cparentno
where us.ctype = "JOBSITE"
&& us.csiteno != null
&& us.csiteno != string.Empty
&& bill.smid = '22'
order by us.csiteno
select new
{
us.ccustno.Trim(),
us.dispname.Trim(),
us.csiteno.Trim(),
so.s1_name.Trim()
}).Distinct();
// to check the translation result
string sql = query.ToString()
// to get the results
var result = query.ToList()
If this is not working for you, you can always fall back to Telerik Data Access ADO.NET API. Here is a documentation article how to use it.

Linq query to SQL query

I have a Linq Query that works well but I need to write the SQL Query
Can Anybody help me write it?
this query will search the database foreach a.h and a.HV in the view with the filters of time and model and in the end it checks the option Filter.M that if it is selected it will search for all the data selected in this DropDownCheckBoxes`
How can i write the this where and select part in SQL command?
ret1 = (from a in View
where
a.LastRefreshTime>=Filter.From && a.LastRefreshTime<=Filter.To && a.ModelCode == mdlCode &&
Filter.PN.Select(epn => epn.Substring(0, 11)).Contains(a.H) &&
Filter.PN.Select(epn => epn.Substring(14, 2)).Contains(a.HV)
select new RData
{
v = a.v,
Date = a.LastRefreshTime,
UserId = a.UserId,
M = a.Name,
}).Distinct().AsQueryable();
ret = ret1.Where(nr =>
Filter.M == null || !Filter.M.Any() || Filter.M.Contains(nr.M)
).ToList();
Here's a start for you
select a.v v,
a.LastRefreshTime "Date",
a.UserId,
a.Name
from a
where a.LastRefreshTime>= arg_filter_from
and a.LastRefreshTime<= arg_filter_to
and a.ModelCode = arg_mdlCode
.
.
.
In this query you'll need to replace 'arg_...' with the appropriate values or arguments you want.
Contains is roughly equivalent to "IN" in SQL. For example:
where a.Name in ('jim', 'bob', 'joe')
In can also be used with a subselect which is roughly what I think Filter.PN.Select is doing though I'm not a linq expert. Example:
where a.H in (Select foo from PN_Table)
Or simpler example continuing on the my previous name example:
where a.Name in (select first_name from table)
If we supposed that the Filter.PN list represent a table FilterPN in your sql database, that will be your converted code for the first linq query
select distinct a.v, a.LastRefreshTime, a.UserId, a.Name
from [view] a
where a.LastRefreshTime>= 'Filter.From' and
a.LastRefreshTime<='Filter.To' and a.ModelCode = 'mdlCode' and
exists(select top 1 * from FilterPN where Substring(epn, 1, 11) = a.H) and
exists(select top 1 * from FilterPN where Substring(eenter code herepn, 15, 2) = a.HV)
think to replace the enquoted variables with ur real values 'Filter.To'...

Multiple where statements in Entity Framework

Database structure sample:
Department Table
-DepartmentID
Facility Table
-Facility ID
-DepartmentID (FK)
-Block
-Level
-Name
-etc
I am trying to select from database from the EF using two where clause. I am not sure what went wrong at the where clause. I am stuck at it. Please help and advice. I have googled on the internet but cannot find the solution to it.
string departmentID = "SIT";
string block = "L";
string level = "4";
string name = "L.425";
using (var db = new KioskContext())
{
var facilitys = from f in db.Facilitys
Where clause to select departmentID where equals to SIT and also where any block or level or name contains any alphabets. Please advice how should i write the statement with two where clause. Thank You!
where f.Department.DepartmentID == departmentID
&& (f.Block.Contains("%" + block + "%") || f.Level.Contains("%" + level + "%")
|| f.Name.Contains("%" + name + "%"))
Remaining of the query statement to select all the facilities
orderby f.FacilityID
select new
{
f.FacilityID,
f.DepartmentID,
f.Description,
f.Block,
f.Level,
f.Name,
f.OpenHours,
f.CloseHours,
f.MaxBkTime,
f.MaxBkUnits,
f.MinBkTime,
f.MinBkUnits
};
foreach (var fac in facilitys)
{
FacObject facobject = new FacObject(fac.FacilityID, fac.DepartmentID, fac.Description, fac.Block, fac.Level,
fac.Name, fac.OpenHours, fac.CloseHours, fac.MaxBkTime, fac.MaxBkUnits, fac.MinBkTime, fac.MinBkUnits);
sqlFacList.Add(facobject);
}
}
Remove the "%" from the various Contains clauses, they are SQL cruft you do not need.
where f.Department.DepartmentID == departmentID
&& (f.Block.Contains(block)
|| f.Level.Contains(level)
|| f.Name.Contains(name ))
Remember LINQ is not just for SQL!

SELECT NEW with a potentially null field using LINQ and Entity Framework

I want to quickly select some rows, format it nicely for a dropdownlist/selectlist or something like that - but I have a field in the db, that is nullable (DateOfBirth).
var athletes = (from at in _db.Athletes
select new{
Name = at.Name + " " + at.DateOfBirth,
Id = at.AthleteId
}).ToList();
Is there a way to handle nullable types inside the LINQ in a case like this?
Edit:
I was not paying attention to the fact, that since this is using entity framework, methods that work with standard LINQ cannot be used unless they have a SQL translation.
DateOfBirth is a Nullable < DateTime >
Source is Entity Framework 4
You can use the null coalesce operator, see Equivalent of SQL ISNULL in LINQ?.
Something like:
var athletes = (from at in _db.Athletes
select new{
Name = at.Name + " " + (at.DateOfBirth ?? ""),
Id = at.AthleteId
}).ToList();
Often a nullable can be handled using variable ?? default
var res = nullableVariable ?? defaultValue;
But be carefull with datetime, linq will try to implement this in SQL and DateTime.MinValue from C# is not within the valid range for SQL and will give you an error message.
Since you are just doing string appending try this.
var athletes = (from at in _db.Athletes
select new{
Name = at.Name + " " + (at.DateOfBirth ?? string.Empty),
Id = at.AthleteId
}).ToList();
In VB.NET
Dim athletes = (From at In _db.Athletes
Select New With{
.Name = at.Name + " " + If(at.Field(Of Object)("DateOfBirth") = Nothing, string.Empty, at.Field(Of Object)("DateOfBirth")),
.Id = at.AthleteId
}).ToList()

Categories