ExpressionToSQL produces invalid query - c#

I am using Dapper with ExpressionToSQL nuget package. I have a query as below:
Set = new Table{Schema = "Sch",Name = "tbl1"};
Columns = x => new { x.Id};
Conditions = x => x.Name== request.Name && x.Date == request.Date;
Where<TQueryIn, object> query = Sql.Select(Columns, Set).Where(Conditions);
...
connection.QueryAsync(query);
Where the value for request.Name is "T1" and request.Date is "20121020".
When I run the above-mentioned query, I get the following query:
SELECT a.[Id] FROM [Sch].[tbl1] AS a WHERE a.[Name] = #Name AND a.[Date] = #Date
As you see the request.Name and request.Date's values are replaced with #Name and #Date!
What I need to see is:
SELECT a.[Id] FROM [Sch].[tbl1] AS a WHERE a.[Name] = 'T1' AND a.[Date] = '20121020'
Definitely this is not a problem with Dapper and it is a problem with ExpressionToSQL package.
Is there any way to overcome this issue, and convert Expression<Func<T,bool>> to a string value with above mentioned output?

I'm not familiar with Dapper, but after looking at the tests in ExpressionToSQL it seems that you can provide the parameters on the second argument of QueryAsync, therefore, I think this should work:
Set = new Table{Schema = "Sch",Name = "tbl1"};
Columns = x => new { x.Id};
Conditions = x => x.Name== request.Name && x.Date == request.Date;
Where<TQueryIn, object> query = Sql.Select(Columns, Set).Where(Conditions);
...
connection.QueryAsync(query, request);
Also found this, may be useful:
https://dapper-tutorial.net/parameter-anonymous

Related

Lambda Select Columns Without an Expression

I want an EF query to return an entire column, but I want to choose that column with a variable. Can that be done? I.E. use a variable instead of a lambda expression as such:
FieldValues = db.PbiData
.Where(x => DatasetList.Contains(x.DatasetId))
.Select(FieldName)
.ToList()
FieldName will always match one of the column names of the PbiData table. For example, the first FieldName value is "Department", and the query below works just fine:
FieldValues = db.PbiData
.Where(x => DatasetList.Contains(x.DatasetId))
.Select(x=>x.Department)
.ToList()
The where clause in each of these queries simply restricts the data returned to the data relevant to the current user.
My attempt, per a comment below:
foreach(var F in model.FieldMetaData)
{
if (F.FieldType == "String")
{
PbiFieldData PbiFieldData = new PbiFieldData()
{
FieldName = F.FieldName,
FieldValues = await db.PbiData.Where(x => DatasetList.Contains(x.DatasetId)).Select(F.FieldName).ToListAsync()
};
model.PbiData.Add(PbiFieldData);
};
}
yes, you can use Expression
ParameterExpression param = Expression.Parameter(typeof(Table), yourVariable);
MemberExpression propExpression = Expression.PropertyOrField(param, yourVariable);
Expression<Func<Table, string>> selector = Expression.Lambda<Func<Table, string>>(propExpression, param);
var result = db.Table.Select(selector).First();
You could use System.Linq.Dynamic Nuget for the purpose
var fieldName = "Department";
var results = context.PbiData
.Where(x=> DatasetList.Contains(x.DatasetId))
.Select(fieldName);
Based on comment, to convert to List, one can use
var results = await context.PbiData
.Where(x=> DatasetList.Contains(x.DatasetId))
.Select(fieldName).ToListAsync();
You can write native sql query:
var FieldValues = ctx.Database.SqlQuery<string>
(
$#"select {fieldName} from PbiData
where DatasetId in ({string.Join(", ", DatasetList.Select(x => $"'{x}'"))})"
).ToList();

C# no coercion operator is defined between types anonymous object

I'm currently working on a LINQ query in an ASP.NET 4.5 application. I try to query 2 lists from different talbles, union the results and return an IQueryable of the data type of the first table.
The tables in my database have similar fields, so i can just select into an anonymous object what I need.
My query looks like this:
var coolStuff = ctx.CoolStuffTable.Select(x => new
{
PK = x.PK,
CreationDate = x.CreationDate,
ModificationDate = x.ModificationDate,
Titel = x.Title,
Visible = x.Visible
});
var niceStuff = ctx.NiceStuffTable.Select(x => new
{
PK = x.PK,
CreationDate = x.CreationDate,
ModificationDate = x.ModificationDate,
Title = x.Title,
Visible = x.Visible
});
var result = coolStuff.Union(nicelStuff)
.Where(i => i.Visible);
var result = result.Cast<CoolStuffTable>(); // the LinqToSQL class of thable CoolStuffTable is also called CoolStuffTable
It looks actually quite good, nevertheless I'm getting this stra
No coercion operator is defined between types
Of course, I could write a view in SQL server, but I'd like to solve this in LINQ...
Do you know how to query 2 different tables, union them and return them as of type table 1 (CoolStuffTable)?
Thank you!!!
You need to project to CoolStuffTable again like
var result = coolStuff.Union(nicelStuff)
.Where(i => i.Visible)
.Select(s => new CoolStuffTable
{
PK = s.PK,
CreationDate = s.CreationDate,
ModificationDate = s.ModificationDate,
Title = s.Title,
Visible = s.Visible
});

C# ?? operator and ora-12704: character set mismatch

I have asp.net mvc 4 application with EF 4, .net 4
This code
public List<ListItem> GetViolatedArticlesByLaw(int lawId, string culture)
{
culture = culture.ToLower();
var ans =
(from art in context.TITLENORMALAWs.Where(l => l.PARENTID == lawId)
select new ListItem
{
ID = art.ID,
ParentID = lawId,
Value = (art.NUM_STATSTR ?? ""),
});
Debug.WriteLine( ((System.Data.Objects.ObjectQuery)ans).ToTraceString() );
return ans.ToList();
}
throws ora-12704: character set mismatch.
It runs perfectly fine if I select from List, like this: from art in context.TITLENORMALAWs.Where(l => l.PARENTID == lawId).ToList()
This is the SQL generated:
SELECT
"Extent1"."ID" AS "ID",
:p__linq__1 AS "C1",
CASE WHEN ("Extent1"."NUM_STATSTR" IS NULL) THEN '' ELSE "Extent1"."NUM_STATSTR" END AS "C2"
FROM "AISSMK"."TITLENORMALAW" "Extent1"
WHERE ("Extent1"."PARENTID" = :p__linq__0)
It produces the same error in sqldeveloper and if I change this piece THEN '' ELSE to this THEN n'' ELSE it runs ok.
NUM_STATSTR in table definition is NVARCHAR2(30)
How can I make linq generate proper sql? Or do I have to call ToList() before selecting and there is no other way?
#Orif I think you should try to build the query manually instead of using the LINQ-to-SQL generators.
Try using the ExecuteQuerymethod on the DataContext class and try to add a cast to NVARCHAR
For more help read here, https://social.msdn.microsoft.com/Forums/en-US/20d456f0-9174-4745-bbc5-571f68879e27/net-strings-sql-paramater-type-always-nvarchar?forum=linqtosql
In my case, the issue was that empty strings are treated as null by Oracle, so your code Value = (art.NUM_STATSTR ?? "") actually ends up looking like Value = (art.NUM_STATSTR ?? null). Our workaround looks like this:
var ans =
(from art in context.TITLENORMALAWs
where art.PARENTID == lawId
select new
{
ID = art.ID,
ParentID = lawId,
Value = (art.NUM_STATSTR ?? ""),
})
.ToList()
.Select(a => new ListItem{
ID = a.ID,
ParentID = a.ParentID,
Value = a.Value ?? "",
});

Entity Framework Query Nested Query

I am new to the entity framework and am trying to convert the following query into the correct function calls.
Select Distinct a.nodeId FROM
(SELECT *
FROM reportContents
Where fitId = '29' and reportId =
(select max(reportId)
from reportContents
where fitId = '29')
) a Where (a.nodeId IS NOT NULL)
I know this query does what i want, however i'm not sure how to translate that into the entitiy framework!
Here was my attempt.
var prevSelectedNodes = db.reportContents.Where(
f => f.fitId == id).Select(
f => f.nodeId).Distinct().ToList();
I need to somehow put a .Select() in the where call. However that kind of thing dosen't seem possible
Thank you in advance!
As you can't make two LINQ nested lambda expression. You can do it with two requests :
var maxReportId = db.reportContents.Where(r => r.fitId = "29").Max(r => r.RepordId);
var result = db.reportContents.Where(r => r.fitId == "29" && r.reportId == maxReportId && r.nodeId != null).Select(a => a.nodeId).Distinct().ToList() ;

Can't Concatenate String in LINQ query

I am just trying to concatenate a string on to a column returned from the database like so:
var aaData =
(from pr in ctx.PaymentRates
where pr.ServiceRateCodeId == new Guid("BBCE42CB-56E3-4848-B396-4656CCE3CE96")
select new
{
Id = pr.Id,
Rate = pr.YearOneRate + "helloWorld"
})
.ToList();
It gives me this error:
Unable to cast the type 'System.Nullable`1' to type 'System.Object'.
LINQ to Entities only supports casting EDM primitive or enumeration
types.
So, then I tried this:
var aaData =
(from pr in ctx.PaymentRates
where pr.ServiceRateCodeId == new Guid("BBCE42CB-56E3-4848-B396-4656CCE3CE96")
select new
{
pr = pr
})
.AsEnumerable()
.Select(x => new
{
Id = x.pr.Id,
Rate = x.pr.YearOneRate + "helloWorld"
})
.ToList();
But, now it gives me this error:
Object reference not set to an instance of an object.
On this line:
.Select(x => new
How can I concatenate these strings in LINQ?
The quick solution
Regarding your second code chunk I need to point out to you that you're actually doing two left outer joins on the Countries table/set, one for homeC and one for hostC.
That means that you are willing to accept null values for those two variables.
In other words, since they can be null you are somehow allowing this right here to crash with NullReferenceException, should those variables turn out to be null:
.Select(x => new
{
Id = x.pr.Id,
HomeCountry = x.homeC.Name,
HostCountry = x.hostC.Name,
Rate = x.pr.YearOneRate + "helloWorld"
})
The error (NullReferenceException or as you saw it's message: "Object reference not set to an instance of an object.") is not here
.Select(x =>
but rather here
x.homeC.Name and x.hostC.Name
where you will most certainly dereference a null reference.
That's just Visual Studio's way of pointing out the best statement that fits around the error.
So, the quickest solution would be to do this:
.Select(x => new
{
Id = x.pr.Id,
HomeCountry = (x.homeC != null) ? x.homeC.Name : "HomeCountry not found",
HostCountry = (x.hostC.Name != null) ? x.hostC.Name : "HostCountry not found",
Rate = x.pr.YearOneRate + "helloWorld"
})
Notice the modification which ensures that you will still be able to extract some information from result set records for which homeC and hostC are null.
EDIT
Regarding the first query you posted:
var aaData =
(from pr in ctx.PaymentRates
where pr.ServiceRateCodeId == new Guid("BBCE42CB-56E3-4848-B396-4656CCE3CE96")
select new
{
Id = pr.Id,
Rate = pr.YearOneRate + "helloWorld"
})
.ToList();
my guess is that your 'YearOnRate' property is of type 'Nullable< of something >" (maybe decimal -- so for instance it is maybe a decimal? YearOnRate { get; set; }) and the corresponding column in the database is a nullable one.
If that is the case, then I think (in this first version of your endeavour) you could try to do this:
Rate = (pr.YearOnRate != null) ? pr.YearOneRate.Value + "helloWorld" : "[null]helloWorld"
and get away with it.
My guess is that either x.homeC, x.hostC, or x.pr are null. If you're fine using AsEnumerable to convert to Linq-to-Objects then you could just change your projection to
.Select(x => new
{
Id = (x.pr.HasValue ? x.pr.Id : 0),
HomeCountry = (x.homeC.HasValue ? x.homeC.Name : null),
HostCountry = (x.hostC.HasValue ? x.hostC.Name : null),
Rate = (x.pr.HasValue ? x.pr.YearOneRate : null) + "helloWorld"
})
My problem was, I wasn't using .AsEnumerable() properly. The code below works:
var aaData =
(from pr in ctx.PaymentRates
from homeC in ctx.Countries.Where(x => x.Id == pr.HomeCountryId).DefaultIfEmpty()
from hostC in ctx.Countries.Where(x => x.Id == pr.HostCountryId).DefaultIfEmpty()
from curr in ctx.Currencies.Where(x => x.Id == pr.YearOneCurrencyId).DefaultIfEmpty()
where pr.ServiceRateCodeId.Value.Equals(new Guid("BBCE42CB-56E3-4848-B396-4656CCE3CE96"))
select new { pr, homeC, hostC, curr })
.AsEnumerable()
.Select(x => new
{
Id = (string)(x.pr.Id.ToString() + "test"),
HomeCountry = (x.homeC != null ? x.homeC.Name : ""),
HostCountry = (x.hostC != null ? x.hostC.Name : ""),
Rate = (x.pr.YearOneRate ?? 0) + " (" + x.curr.Code + ")"
})
.ToList();
You have used DefaultIfEmpty on both homeC and hostC so you can get a null reference when you call homeC.Name or hostC.Name
Try using HomeCountry = homeC == null ? null : homeC.Name instead
If pr.YearOneRate is not a string and you want the concatenation done by the database engine you need to tell Linq-to-Entities to generate sql to convert it. If you are using Sql Server you can use this:
SqlFunctions.StringConvert(pr.YearOneRate) + "helloWorld"
If you don't need the concatenation done in the database then you can use AsEnumerable() before the Select so that you are running Linq-To-Objects

Categories