I have a string with Names seperated by comma and I need to perform Select Operation Using In clause for the string I have..
here is my Code
protected void btnSubmitt_Click(object sender, EventArgs e)
{
try
{
List<string> ids = new List<string>();
for (int i = 0; i < RadListBox2.Items.Count; i++)
{
ids.Add(RadListBox2.Items[i].Text);
}
string result = string.Join(",", ids);
//result I have Data Something like This
result=name1,name2
var ProductAttributeRowId = string.Join(",", from m in dt.AsEnumerable() where m.Field<string>("ProductAttributeName") in result select m.Field<long>("ProductAttributeRowId"));
string json = "{'ProductRowId':" + hdnId.Value+ ",'ProductAttributeRowId':'" + ProductAttributeRowId +"'}";
statuslabel.Text = ClsUtility.HttpPost(url + "Services/Product.svc/ProductAttributesID", json);
}
catch (Exception Err)
{
}
BindGrid();
}
it shows the error when I used 'in' Linq Query pls help me
Why do you concatenate the ID's with comma if you need to split them two lines behind?
Use Contains with the original list, i guess this is what you want:
var ProductAttributeRowId = dt.AsEnumerable()
.Where(row => ids.Contains(row.Field<string>("ProductAttributeName")))
.Select(row => row .Field<long>("ProductAttributeRowId"));
To perform a IN query, use the following syntax:
var array = new List<String>(...);
var contains = (from elm in collection where array.Contains(elm)).Any();
That is, you invert the logic: a collection containing values contains your iterator variable.
var ProductAttributeRowId =string.Join("," ,dt.AsEnumerable()
.Where(row => ids.Contains(row.Field<string>("ProductAttributeName")))
.Select(row => row.Field<long>("ProductAttributeRowId")));
Related
sonar is given me a hard time because the following code:
var listaChaves = chaves.ToList();
var parametros = new string[chaves.Count];
var parametrosSql = new List<NpgsqlParameter>();
for (int i = 0; i < listaChaves.Count; i++)
{
parametros[i] = string.Format("#param_{0}", i);
parametrosSql.Add(new NpgsqlParameter(parametros[i], listaChaves[i]));
}
var comandoSql = string
.Format("SELECT distinct on(chave_identificacao) chave_identificacao, data from ultimos_acessos where chave_identificacao in({0}) order by chave_identificacao, data desc",
string.Join(", ", parametros));
var ultimosAcessos = await Entidade.FromSqlRaw(comandoSql, parametrosSql.ToArray())
.Select(a => new ProjecaoListagemUltimoAcesso(a.Data, a.ChaveIdentificacao))
.ToListAsync();
it thinks a sql injection can happen because the string interpolation. So i tried to change to "FromSqlInterpolated" method, as follow:
var listaChaves = chaves.ToList();
var ultimosAcessos = await Entidade.FromSqlInterpolated(#$"SELECT distinct on(chave_identificacao) chave_identificacao, data from ultimos_acessos where chave_identificacao in({string.Join(", ", listaChaves)})) ) order by chave_identificacao, data desc")
.Select(a => new ProjecaoListagemUltimoAcesso(a.Data, a.ChaveIdentificacao))
.ToListAsync();
But it just dont work, anyone can help me on how can I create a secure sql from a interpolated string using a "in" clause?
Something like this should work. Build an OR clause in the same loop as your parameters and stuff it into your SQL:
string ORclause = "";
for (int i = 0; i < listaChaves.Count; i++)
{
ORclause += $" chave_identificacao = #param_{i} OR ";
parametros[i] = string.Format("#param_{0}", i);
parametrosSql.Add(new NpgsqlParameter(parametros[i], listaChaves[i]));
}
//remove last "OR"
ORclause = ORclause.Substring(0, s.Length - 4);
#$"SELECT distinct on(chave_identificacao) chave_identificacao, data
from ultimos_acessos
where {ORclause}
order by chave_identificacao, data desc";
If you have a lot of listaChaves then consider using StringBuilder instead of +=
I have been learning C# (I am relatively new) and I have a list of input files consisting file naming format like "inputFile_dateSequence_sequenceNumber.xml". The code that I am using to sort the file lists in ascending order is below:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
string[] inputfiles = { "inputFile_2020-04-10_1.xml",
"inputFile_2020-04-10_2.xml",
"inputFile_2020-04-10_4.xml",
"inputFile_2020-04-10_3.xml",
"inputFile_2020-04-10_10.xml",
"inputFile_2020-05-10_1.xml",
"inputFile_2020-05-10_2.xml",
"inputFile_2020-05-10_10.xml",
"inputFile_2020-05-10_11.xml" };
List<string> stringList = new List<string>();
foreach (string s in inputfiles)
{
string bz = s.Split('.')[0];
stringList.Add(bz);
}
string[] Separator = new string[] { "_" };
var sortedList = stringList.OrderBy(i => i).ThenBy(s => int.Parse(s.Split(Separator, StringSplitOptions.None)[2])).ToList();
foreach (string i in sortedList)
{
Console.WriteLine(i);
}
}
}
But in ascending order, I am getting output as below:
inputFile_2020-04-10_1
inputFile_2020-04-10_10
inputFile_2020-04-10_2
inputFile_2020-04-10_3
inputFile_2020-04-10_4
inputFile_2020-05-10_1
inputFile_2020-05-10_10
inputFile_2020-05-10_11
inputFile_2020-05-10_2
but my desired output is like below:
inputFile_2020-04-10_1.xml
inputFile_2020-04-10_2.xml
inputFile_2020-04-10_3.xml
inputFile_2020-04-10_4.xml
inputFile_2020-04-10_10.xml
inputFile_2020-05-10_1.xml
inputFile_2020-05-10_2.xml
inputFile_2020-05-10_10.xml
inputFile_2020-05-10_11.xml
What modification should the code need in order to get the output like this?
You could achieve your need by using regex:
var sortedList= stringList.OrderBy(x => Regex.Replace(x, #"\d+", m => m.Value.PadLeft(10, '0')));
Loads of ways to solve this, as you can see...
You can order first by just the date part of the name, then by the length of the name string, so smaller numbers like 1, 7 sort before longer numbers like 10, 17.. then by the name itself
.OrderBy(x => x.Remove(20))
.ThenBy(x=>x.Length)
.ThenBy(x=>x)
Perhaps though you'd parse the entire thing:
class MyFile{
string FullName {get;set;}
string Name {get;set;}
DateTime Date {get;set;}
int Num {get;set;}
MyFile(string fullname){
var bits = Path.GetFilenameWithoutExtension( fullname).Split('_');
FullName = FullName;
Name = bits[0];
Date = DateTime.Parse(bits[1]);
Num = int.Parse(bits[2]);
}
Then
var parsed = inputfiles.Select(x => new MyFile(x));
Now you can OrderBy that:
parsed.OrderBy(m => m.Date).ThenBy(m => m.Num);
Try to avoid doing everything at some base level of string/int primitive; this is OO programming! 😀
Use the following code:
var sortedList = stringList
.OrderBy(s => s.Substring(0, s.LastIndexOf('_'))) // sort by inputFile_dateSequence
.ThenBy(s => int.Parse(s.Substring(s.LastIndexOf('_') + 1))) // sort by sequenceNumber as integer
.ToList();
Update. If you want to preserve file extension, you can use the following:
List<string> sortedList = inputfiles
.Select(s =>
{
int nameSeparator = s.LastIndexOf('_');
int extSeparator = s.LastIndexOf('.');
return new
{
FullName = s,
BaseName = s.Substring(0, nameSeparator),
Sequence = int.Parse(s.Substring(nameSeparator + 1, extSeparator - nameSeparator - 1)),
Extension = s.Substring(extSeparator + 1)
};
})
.OrderBy(f => f.BaseName) // sort by inputFile_dateSequence
.ThenBy(f => f.Sequence) // sort by sequenceNumber
.ThenBy(f => f.Extension) // sort by file extension
.Select(f => f.FullName)
.ToList();
Using DataTable and LinQ may help you to do the task done easier.
Below is the code with DataTable that generate your desire output
public static void Main()
{
string[] inputfiles = { "inputFile_2020-04-10_1.xml",
"inputFile_2020-04-10_2.xml",
"inputFile_2020-04-10_4.xml",
"inputFile_2020-04-10_3.xml",
"inputFile_2020-04-10_10.xml",
"inputFile_2020-05-10_1.xml",
"inputFile_2020-05-10_2.xml",
"inputFile_2020-05-10_10.xml",
"inputFile_2020-05-10_11.xml" };
DataTable dt = new DataTable();
dt.Columns.Add("filename", typeof(string));
dt.Columns.Add("date", typeof(DateTime));
dt.Columns.Add("sequence", typeof(int));
foreach (string s in inputfiles)
{
DataRow dr = dt.NewRow();
dr[0] = s;
dr[1] = Convert.ToDateTime(s.Split('_')[1]);
dr[2] = Convert.ToInt32(s.Split('_')[2].Split('.')[0]);
dt.Rows.Add(dr);
}
DataTable sortedDT = dt.AsEnumerable()
.OrderBy(r => r.Field<DateTime>("date"))
.ThenBy(r => r.Field<int>("sequence"))
.CopyToDataTable();
foreach (DataRow dr in sortedDT.Rows)
{
Console.WriteLine(dr[0]);
}
}
Output:
I want to create a dynamic query with LINQ-to-SQL and everything works except for one thing: group by. I looked at the other questions but haven't found a reason so far why it does not work.
I use using System.Linq.Dynamic; with the following query (that works):
int numberOfRankedItems = 3;
string minMaxChoice = "max";
string orderBy = "";
if (minMaxChoice == "max")
{
orderBy = "queryGroup.Sum(row => row.POSITIONVALUE) descending";
} else if (minMaxChoice == "min")
{
orderBy = "queryGroup.Sum(row => row.POSITIONVALUE) ascending";
}
string minMaxFeatureColumnName = "BRANDNAME";
string selectMinMaxFeature = "new { minMaxFeature = queryGroup.Key." + minMaxFeatureColumnName + ", sumPosition = queryGroup.Sum(row => row.POSITIONVALUE)}";
var query = (from tableRow in Context.xxx
where /* some filters */
group tableRow by tableRow.BRANDNAME into queryGroup
orderby orderBy
select selectMinMaxFeature).Take(numberOfRankedItems).ToList();
The use of variables for orderby and select works fine, but for group by not no matter what I try to replace with a variable. The query actually works if I e.g. use a variable instead of tableRow.BRANDNAME but the query returns the wrong result. The goal is to be able to set the column for the grouping dynamically.
Ideas?
Thanks
Edit: there seem to be multiple issues also with the other variables. So I generalize the question a bit: how can I generalize the following query in terms of
The column to group by
The column to order by + ASC or DESC
In the select statement the columnname of the first statement (BRANDNAME)
Here is the query:
var query = (from tableRow in ctx.xxx
where /* filter */
group tableRow by new { tableRow.BRANDNAME } into queryGroup
orderby queryGroup.Sum(row => row.POSITIONVALUE) descending
select new { minMaxFeature = queryGroup.Key.BRANDNAME, sumPosition = queryGroup.Sum(row => row.POSITIONVALUE) }).Take(numberOfRankedItems).ToList();
Would be great without expression trees ;)
I have now elaborated a solution to the question:
The solution uses as before using System.Linq.Dynamic; allows now to set certain variables. In the end it returns a dictionary.
// set variables
int numberOfRankedItems;
if (queryData.NumberOfRankedItems != null)
{
numberOfRankedItems = (int) queryData.NumberOfRankedItems;
} else
{
numberOfRankedItems = 0;
}
string minMaxChoice = queryData.MinMaxChoice;
string minMaxFeatureColumnName = queryData.MinMaxFeatureColumnName;
string orderByPrompt = "";
if (minMaxChoice == "max")
{
orderByPrompt = "it.Sum(POSITIONVALUE) descending";
} else if (minMaxChoice == "min")
{
orderByPrompt = "it.Sum(POSITIONVALUE) ascending";
}
string groupByPrompt = queryData.MinMaxFeatureColumnName;
// execute query
IQueryable query = (from tableRow in Context.xxx
where /* some filters */
select tableRow).
GroupBy(groupByPrompt, "it").
OrderBy(orderByPrompt).
Select("new (it.Key as minMaxFeature, it.Sum(POSITIONVALUE) as sumPosition)").
Take(numberOfRankedItems);
// create response dictionary
Dictionary<int?, Dictionary<string, int?>> response = new Dictionary<int?, Dictionary<string, int?>>();
int count = 1;
foreach (dynamic item in query)
{
string minMaxFeatureReturn = item.GetType().GetProperty("minMaxFeature").GetValue(item);
int? sumPositionReturn = item.GetType().GetProperty("sumPosition").GetValue(item);
response[count] = new Dictionary<string, int?>() { { minMaxFeatureReturn, sumPositionReturn } };
count++;
}
return response;
I have a DataTable as shown below:
After using below LINQ Expression on above DT:
if (dt.AsEnumerable().All(row => string.IsNullOrEmpty(row.Field<string>("SameReferences"))))
BindOldReferences(dt);
else
{
var grps = from row in dt.AsEnumerable()
let RefID = row.Field<string>("ReferenceID")
let RefDescription = row.Field<string>("ReferenceDescription")
let ReferenceUrl = row.Field<string>("ReferenceUrl")
let SortOrder = row.Field<int>("sortOrder")
group row by new { RefDescription, ReferenceUrl, SortOrder } into groups
select groups;
dt = grps.Select(g =>
{
DataRow first = g.First();
if (first.Field<string>("SameReferences") != null)
{
string duplicate = first.Field<int>("SortOrder").ToString();
first.SetField("SameReferences", string.Format("{0},{1}", duplicate, first.Field<string>("SameReferences")));
}
return first;
}).CopyToDataTable();
}
After applying above LINQ to DT it becomes :
Expected DT as below : eliminate (,) comma when there is single value in column Samereferences. So what changes i have to make to LINQ to get the expected below output.
Please help..!
You can use String.Trim method like this:-
first.SetField("SameReferences", string.Format("{0},{1}", duplicate,
first.Field<string>("SameReferences")).Trim(','));
It will remove all the trailing comma.
Try this:
if (first.Field<string>("SameReferences") != null)
{
string duplicate = first.Field<int>("SortOrder").ToString();
string sameReference = first.Field<string>("SameReferences");
if (String.IsNullOrEmpty(sameReference))
first.SetField("SameReferences", duplicate);
else
first.SetField("SameReferences", string.Format("{0},{1}", duplicate, sameReference));
}
I have 2 entities Line and Tag. The relation is Line *----* Tag
From line I have a navigation property Line.Tags which returns a list of Tag objects. The Tag.Name is the string value im after.
What I really need is to get all the tag names in a comma seperated way like so :
tag1, tag2, tag3
I tried to do this in a projection, but it said it doesnt support toString()
var o = dgvLines.CurrentRow.DataBoundItem as Order;
var r = _rs.Lines.Where(y => y.InvoiceNo == o.InvoiceNo).Select(x => new
{
ReturnNo = x.Return.ReturnNo,
Part = x.Part,
Tags = String.Join(", ", x.Tags.ToList().Select(t => t.Name))
});
dgvExistingParts.DataSource = r;
Error:
LINQ to Entities does not recognize the method 'System.String Join(System.String, System.Collections.Generic.IEnumerable`1[System.String])' method, and this method cannot be translated into a store expression.
Any idea how I can get this comma separated list of tags?
Thanks in advance.
var r = _rs.Lines.Where(y => y.InvoiceNo == o.InvoiceNo).ToList().Select(x => new
{
ReturnNo = x.Return.ReturnNo,
Part = x.Part,
Tags = String.Join(", ", x.Tags.Select(t => t.Name))
});
You can't do the concatenation in SQL, so you have to get back the data you need and then work in normal code:
var o = dgvLines.CurrentRow.DataBoundItem as Order;
var r = _rs.Lines
.Where(y => y.InvoiceNo == o.InvoiceNo)
.Select(x => new
{
ReturnNo = x.Return.ReturnNo,
Part = x.Part,
TagNames = x.Tags.Select( t => t.Name ),
}
)
.ToList() // this runs the SQL on the database
.Select( x => new
{
ReturnNo = x.ReturnNo,
Part = x.Part,
Tags = String.Join( ", ", x.TagNames ),
}
)
.ToList();
dgvExistingParts.DataSource = r;