I'm trying to use a Dynamic LINQ Query to query a SQL database, and in the Where clause I need to evaluate an '=' condition with a field that is of type TEXT.
Right now, I've got this:
var result = DBCon.PcInValue
.Where(String.Format("InputName = #0 and InputValue) {0} #1", f.Condition), f.Field, f.Value)
.Select("new(OrderNum, OrderLine)");
This doesn't work since you can't use the equal operator on a TEXT data type.
The field that is type TEXT is "InputValue". I tried to convert it like so:
var result = DBCon.PcInValue
.Where(String.Format("InputName = #0 and Convert(nvarchar(100), InputValue) {0} #1", f.Condition), f.Field, f.Value)
.Select("new(OrderNum, OrderLine)");
But it looks like this is not supported.
Anyone have any clues as to how I can do this?
EDIT:
The following SQL Syntax works with no issues, but again I'm not sure if this is possible using the Dynamic LINQ API:
SELECT [t0].[OrderNum], [t0].[OrderLine]
FROM [PcInValue] AS [t0]
WHERE ([t0].[InputName] = 'OpenWidthFt') AND (Convert(nvarchar(100), [t0].[InputValue]) = '10')
I've tested this and it seems to work fine (though it's a bit odd):
var result = DBCon.PcInValue
.Where(String.Format("InputName = #0 and InputValue.ToString() {0} #1", f.Condition), f.Field, f.Value)
.Select("new(OrderNum, OrderLine)");
LinqPad tells me it's translated into something similar to the following (using my own table):
SELECT [t0].[Id], [t0].[Name], [t0].[InputValue]
FROM [People] AS [t0]
WHERE (CONVERT(NVarChar(MAX),[t0].[InputValue])) = #p0
Related
Hello How to i do a LINQ of a SQL Query Like this:
SELECT
c.Value as IPAddress,
cd.Number as PrintNo,
cd.TerminalNumber as TerminalNo
FROM
configuration c,
ConfigurationDevice cd
WHERE
c.DeviceID=cd.ConfigurationDeviceID
AND Parameter = 'IPAddress'
AND DeviceID IN (
SELECT
ConfigurationDeviceID
FROM
ConfigurationDevice
WHERE
[Type]=1
AND TerminalNumber > 0
)
Can anyone show a LINQ from Simple to a Lambda Expression of this Kind of SQL Query where another SQL Statement Declaration is done inside a SQL Query Statement.
Also this is what i've done so far but i also got an error on calling out the result column.
First, if you're going to write SQL, please write it as ANSI SQL and not Oracle SQL. ANSI SQL is more widely supported.
ANSI SQL version
SELECT
IPAddress as Value,
cd.Number,
cd.TerminalNumber
FROM
-- also flipped the root as it seem to make more sense to me
ConfigurationDevice cd
join configuration c on cd.ConfigurationDeviceID=c.DeviceID
WHERE
Parameter = 'IPAddress'
AND DeviceID IN (
SELECT
ConfigurationDeviceID
FROM
ConfigurationDevice
WHERE
[Type]=1
AND TerminalNumber > 0
)
You haven't shown anything about what you have entity-wise.
Entities
Configuration
ConfigurationDevice
var subQuery = (
from cd in ctx.ConfigurationDevice
where
cd.Type ==1
&& cd.TerminalNumber > 0
select
cd.ConfigurationDeviceID
);//.ToList();
var query = (
from cd in ctx.ConfigurationDevice
join c in ctx.Configuration on cd.ConfigurationDeviceID equals c.DeviceID
where
c.Parameter == "IPAddress"
&& subQuery.Contains(c.DeviceID)
select new //Add a type here
{
Value = c.IPAddress,
Number = cd.Number,
TerminalNumber = cd.TerminalNumber
});
var result = query.ToList();
I have a situation where the translated sql direct form Visual Studio is returning a different number of records from the Linq. I am expecting 4 items but in the count() of the resulting list I only have 1. This is the case despite creating more records - it always returns 1.
db.DCLVUnknowns.Where(x => x.DCLVUnknownId == Report.DCLid).ToList();
SELECT
[Extent1].[DCLVUnknownId] AS [DCLVUnknownId],
[Extent1].[Gender] AS [Gender],
[Extent1].[Height] AS [Height],
[Extent1].[Weight] AS [Weight],
[Extent1].[Age] AS [Age],
[Extent1].[Race] AS [Race],
[Extent1].[DCLid] AS [DCLid]
FROM [dbo].[DCLVUnknown] AS [Extent1]
Strange thing is I have the same linq expression running fine for other entities and there is no problem. It is consistently happening at the same spot every time.
db.DCLVUnknowns
Is a query of the entire table, not the query for what you want.
If you want to inspect the IQueryable of the full query, try:
var results = db.DCLVUnknowns.Where(x => x.DCLVUnknownId == Report.DCLid);
var theResultSet = results.ToList();
Here results should translate as roughly:
SELECT
[Extent1].[DCLVUnknownId] AS [DCLVUnknownId],
[Extent1].[Gender] AS [Gender],
[Extent1].[Height] AS [Height],
[Extent1].[Weight] AS [Weight],
[Extent1].[Age] AS [Age],
[Extent1].[Race] AS [Race],
[Extent1].[DCLid] AS [DCLid]
FROM [dbo].[DCLVUnknown] AS [Extent1]
WHERE [Extent1].[DCLVUnknownId] = DCLid
Assuming DCLVUnknownId is a PK/ Identity, you should see one result in theResultSet.
I was hoping to be able to write most of the query in LINQ, but then write the WHERE clause as a string, like you would a dynamic query. So something like:
var query = from part in _context.CurrentInventory
query.Where = "part.PartNumber LIKE '%a%' OR part.PartNumber LIKE '%b%'
The reason is because the WHERE can get quite large and using EF.Functions.Like and Contains really slows down the query.
I could build the whole thing dynamically and just execute the string, but I was hoping to avoid that.
You can use System.Linq.Dynamic which is based on previous work
Install-Package System.Linq.Dynamic
The query
query.Where = "part.PartNumber LIKE '%a%' OR part.PartNumber LIKE '%b%'
can be re-written as:
query.Where ("part.PartNumber.Contains(#0) or part.PartNumber.Contains(#1)","a" ,"b")
Working example at fiddle
Update:
I used dynamic Linq with EntityFramework
using (var context = new NorthwindEntities())
{
var customers = context.Customers.Where("ContactName.Contains(#0) or ContactName.Contains(#1)", "Maria","Carine").ToList();
Console.WriteLine(customers.Count);
}
The generated Sql (as seen from sql profiler) is:
SELECT
[Extent1].[CustomerID] AS [CustomerID],
[Extent1].[CompanyName] AS [CompanyName],
[Extent1].[ContactName] AS [ContactName],
[Extent1].[ContactTitle] AS [ContactTitle],
[Extent1].[Address] AS [Address],
[Extent1].[City] AS [City],
[Extent1].[Region] AS [Region],
[Extent1].[PostalCode] AS [PostalCode],
[Extent1].[Country] AS [Country],
[Extent1].[Phone] AS [Phone],
[Extent1].[Fax] AS [Fax]
FROM [dbo].[Customers] AS [Extent1]
WHERE ([Extent1].[ContactName] LIKE N'%Maria%') OR ([Extent1].[ContactName] LIKE N'%Carine%')
The where condition is translated to:
WHERE ([Extent1].[ContactName] LIKE N'%Maria%') OR ([Extent1].[ContactName] LIKE N'%Carine%')
I use asp.net 4 c# and ef4.
I have this code, it should compile a query and return a single scalar value (I use anonymous type).
My code does not have apparently errors, but because is the first time I write a compiled query I would like to know if is well written or could be improved for a performance boost.
var query = CompiledQuery.Compile((CmsConnectionStringEntityDataModel ctx)
=> from o in ctx.CmsOptions
where o.OptionId == 7
select new
{
Value = o.Value
});
uxHtmlHead.Text = query(context).FirstOrDefault().Value;// I print the result in a Label
SQL Profile Output:
SELECT TOP (1)
[Extent1].[OptionId] AS [OptionId],
[Extent1].[Value] AS [Value]
FROM [dbo].[CmsOptions] AS [Extent1]
WHERE 7 = [Extent1].[OptionId]
Many Thanks
Result after Wouter advice (please guys have a double check again):
static readonly Func<CmsConnectionStringEntityDataModel, int, string> compiledQueryHtmlHead =
CompiledQuery.Compile<CmsConnectionStringEntityDataModel, int, string>(
(ctx, id) => ctx.CmsOptions.FirstOrDefault(o => o.OptionId == id).Value);
using (var context = new CmsConnectionStringEntityDataModel())
{
int id = 7;
uxHtmlHead.Text = compiledQueryHtmlHead.Invoke(context, id);
}
Resulting SQL (I do not understand why with a LEFT JOIN)
exec sp_executesql N'SELECT
[Project1].[Value] AS [Value]
FROM ( SELECT 1 AS X ) AS [SingleRowTable1]
LEFT OUTER JOIN (SELECT
[Extent1].[Value] AS [Value]
FROM [dbo].[CmsOptions] AS [Extent1]
WHERE [Extent1].[OptionId] = #p__linq__0 ) AS [Project1] ON 1 = 1',N'#p__linq__0 int',#p__linq__0=7
There are 2 things you can improve on.
First, precompiling a query is definitely a good idea but if you have a look at your code you will see that it precompiles the query each and every time instead of only once.
You need to move the precompiled query to a static variable that is initialized only once.
Another thing you need to be careful of is that when precompiling a query you shouldn't modify the query anymore before executing it.
You are building a precompiled query that will select all rows and then you say 'firstordefault' which changes the precompiled query to a SELECT TOP (1) and you lose the benefit of precompiling. You need to move the FirstOrDefault part inside your precompiled query and return only one result.
Have a look at this documentation. If you look at the examples you can see how they use a static field to hold the compiled query and how they specify the return value.
I get a list of entities to update and I have their ids. I want to get the original ones from the database, so I do:
String[] ids = updatedEvents.Select(ue => ue.id).ToArray();
var originalEventsToUpdate = Db.tbl_ffk_event
.Where(e => ids.Contains(e.id))
.ToArray();
But what I get using the log is this generated SQL:
SELECT [t0].[id], [t0].[fs_mapping_id], [t0].[fs_id_value], [t0].[desc]
FROM [dbo].[tbl_ffk_event] AS [t0]
WHERE 0 = 1
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.1
And that SQL means "get the whole table".
How can I generate a "IN" like this:
SELECT [t0].[id], [t0].[fs_mapping_id], [t0].[fs_id_value], [t0].[desc]
FROM [dbo].[tbl_ffk_event] AS [t0]
WHERE [t0].[id] IN ('aaa','bbb','ccc','ddd','eee',)
Thanks in advance.
EDIT:
I feel stupid, I didn't see the WHERE 0 = 1. It's because at that point, there where nothing in the ids collection. I have checked out now ensuring there are items, and the SQL is generated correctly. Sorry.
Actually, due to the clause WHERE 0 = 1 this SQL will return an empty recordset (i.e. correctly mapped in terms of the schema, but with no rows).
The code you give seems correct, but something has convinced the query provider that there can never be a matching row.
Assuming it's not correct in this, I'd look at the column mapping for the id property. Does it match that of the database correctly?
Probably your list is coming empty, this is the normal behavior of Linq.
Try this:
Dim strval As String = ""
Dim strnum(30) As String
strval = "1,2,3,4,5,6,7,9"
strnum = strval.split(",")
originalEventsToUpdate = (from a in Db.tbl_ffk_event where strnum.contains(a.id) select a).tolist