Select constant and union with another list - c#

I have a Category table with pk and sName columns. I want to add additional row with constant values such as
pk = -1, sName = "NONE"
so that the user can select "NONE" row if they want to.
Below is the code to retrieve Categories,
var catList = from c in context.Category
where c.iStatus == 1 && c.iCat1ID == Cat1ID
select new { c.pk, c.sName };
Below is the code to retrieve constant row,
var noneList = from c in context.Category
select new { pk = -1, sName = " NONE" };
Then I add noneList to the catList by
catList = catList.Union(noneList);
This works fine when there is at least 1 row in Category table. When there are 0 rows in Category table, noneList will not get anything from the query and catList will not have the "NONE" row.
I have searched a lot how to union with a row with constants but I was not able to find an example that satisfies my situation.
Here's another attempt.
var catList = from c in context.Category
where c.iStatus == 1 && c.iCat1ID == Cat1ID
select new { c.pk, c.sName };
var noneList = new[] { new { pk = -1, sName = " NONE" }};
catList = catList.Union(noneList);
This code does not give any errors at design time but when I run it, it throws:
Unable to create a constant value of type 'Anonymous type'. Only primitive types or enumeration types are supported in this context.
[Edit]
By converting catList to an array looks like it does not throw any exception.
var aa = CatList.ToArray().Union(NoneList);
Any other suggestion is appreciated.

Is it Entity Framework? Materialize the query first to perform union in memory. By calling castList.ToArray().Union() (or ToList()).

Related

New to C#, how to update data table (or join table)?

I am new to C# (has experience in other languages before, C++, SQL AutoIT). I have a datatable with 10 columns
Name, MemberNoA, MemberNoB, DriverLicense, MobileNo, Address1, Address2, Address3, ProgramJoinned, Remark
The datatable has around 17,000 rows, what I want to do is, if the same person's records appear more than 2 times in the datatable, put a description in a remark field.
4 criteria to define "same person", any one criteria match will treat as "same person"
i Name + MemberNoA
ii Name + MemberNoB
iii Name + DriverLicense
iv Name + MobileNo
i.e. if there are 3 records with same Name and same MemberNoA, need to put description into remark field of these 3 records.
I work out result set from the above 4 criteria like this:
var resultCriteria1 = from gpr in dt.AsEnumerable()
group gpr by new {
Fld1 = gpr.Field < string > ("Name"),
Fld2 = gpr.Field < string > ("MemberNoA")
}
into grpp
where grpp.Count() > 2
select new {
Name = grpp.Key.Fld1,
MemA = grpp.Key.Fld2,
Cnt = grpp.Count()
};
after that, I loop thru all rows in dt and for each row, loop thru all result set in 4 criteria:
for (int i = 1; i < dt.Rows.Count; i++) {
foreach(var item in resultCriteria1) {
if ((item.Nam == s trName) && (item.MemA == M emberNoA)) {
dt.Rows[i].ItemArray[9] = d t.Rows[i].ItemArray[9] + "Criteria 1 match\r\n";
}
}
}
The program work but run very slow! Is there any method like simple sql statement:
update table1 where
table1.name = table2.name and
table1.MemberNoA = table2.MemberNo2
set table1.Remark = "Criteria 1 match\r\n"
Is there any way to do this in C# or any way to optimize it ? Thanks.
Regds
LAM Chi-fung
The problem is that you are making a cartesian join between the grouped results and the original datatable, without using any performant data structures such as a dictionary or hashset.
But you don't actually need to join it at all, the grouped results can actually hold the relevant data rows directly.
The following code should be performant enough
var grouped =
from gpr in dt.Rows.Cast<DataRow>()
group gpr by (
Fld1: (string)gpr["Name"],
Fld2: (string)gpr["MemberNoA"]
)
into grpp
where grpp.Count() > 2
select grpp;
foreach (var grp in grouped)
foreach (var row in grp)
row["Remark"] += "Criteria 1 match\r\n";
What you can do is to use hashtable, order your data, and then iterate comparing current row data with previous using a cursor. This should give you Log(n) time complexity.

how to combine two data source into one?

i have records in two tables, and 1 object,
i want to retrieve data from both tables into 1 gridview, (both tables have same fields) i can not have joins because i need to show all rows
here is my code:
var query = from all in DB.Movies
where all.IsActive
select new MoviesObject
{
PhotoId = all.PhotoId,
Title = all.Title,
Description = all.ShortDescription
};
var querytwo = from all in DB.movieslisttwo
where all.IsActive
select new MoviesObject
{
PhotoId = all.PhotoId,
Title = all.Title,
Description = all.ShortDescription
;
return query.ToList();
return query.Concat(query2).ToList();
Alternatively, you can call .Union() to skip duplicates.

fill linq null data c# from previous line

I have bill details in list which contains the heading:
Account Numbers, Dates, Service Number, Charge category, Details, exgst, ingst, Detailsfill
Column :- Account Numbers, Dates, Service Number, Charge category, Details, exgst, ingst
are unique values but Column Detailsfill contains null. I want to allow my C# script to set values for Detailsfill where Detailsfill is null then insert data from previous row otherwise do nothing.
Note that Running total sets to 1 when detailsfill column has any text but continues to increment by 1 from 3 when detailsfill column is empty.
Below is the script I used.
var result_set2 = (from a in result_set1
join b in
(from x in result_set1a select x)
on
new {col1 = a.id, col2 = a.account, col3 = a.date, col4 = a.service, col5 = a.chargecat }
equals
new { col1 = b.id, col2 = b.account, col3 = b.date, col4 = b.service, col5 = b.chargecat } into outer
from tb in outer.DefaultIfEmpty()
where a.running_total1 != 0
where a.running_total1 != 2
where a.chargecat != ""
select new
{
running_total = a.running_total1,
account = a.account,
date = a.date,
service = a.service,
chargecat = a.chargecat,
details = a.details,
exgst = a.exgst,
ingst = a.ingst,
detailsfill = ((tb == null) ? "" : tb.details)
}).ToList();
foreach (var line in result_set2)
{
mobilenet_writerfile.WriteLine(line);
}
It sounds to me like you need a correlated subquery to populate detailsfill. This would be in the form of a select from a context with whatever parameters you determine fulfill your requirements. Example on second post of this thread: http://social.msdn.microsoft.com/forums/en-US/linqprojectgeneral/thread/18da37b0-b40e-444e-8ec7-7bd343e0c799/
Also you can find other examples here on stackoverflow: Is it possible to create a correlated subquery in LINQ?
More information would be required to write a contextual example but here is basically what it would look like:
Entities context = new Entities();
context.tbl.Where(t=>t.Id == someId)
.Select(t=> new() {
t.Id,
context.tbl2.First(tbl2=>tbl2.Id == t.Id).Value, //This is the subquery
t.whatever});
This is not a normal operation of Linq to hold onto a previous value and then use it later. That's not to say you can't make that work with Linq, but it would be more straightforward to keep that logic outside of the sequence operation. Simply iterate over the results after the query is composed.
var item = results.First();
foreach (var obj in results)
{
if (obj.detailsfill == null)
obj.detailsfill = item.detailsfill;
item = obj;
}
Note: If the first item happens to contain null in detailsfill, you will not pick up a value until the first item in the sequence that does contain a value. To get the first such item up front, simply use
var item = results.First(o => o.detailsfill != null);
// loop below

taking more than one cells into one cell

I am using a linq query to obtain a table of customers with their total money amount for each monetary unit exist in my database(this one is ok.)
when show the result of my query with Microsoft Report Viewer the result is like Table 1 but what i want is Table 2, only the customer name like "A" and a cell with all the monetory unit records > 0.
Is there any way you can suggest?
This is my code which produces Table 1:
var query = from kur in kurToplamlist
join cariBilg in db.TBLP1CARIs
on kur.CariIdGetSet equals cariBilg.ID
select new
{
cariBilg.ID,//customerid
EUROBAKIYE = cariBilg.HESAPADI,
cariBilg.K_FIRMAADI,//other column names
cariBilg.K_YETKILIADI,//other column names
cariBilg.K_FIRMATELEFON,//other column names
cariBilg.K_YETKILITELEFON,//other column names
AUDBAKIYE = cariBilg.B_CEPTELEFON,//other column names
MonetaryUnit = String.Concat(kur.KurToplamMiktarGetSet.ToString(), kur.DovizTuruGetSet.ToString()),//concatenates "100" and "TL/USD etc."
};
What i want is to obtain Table 2 in the image
Thank you in advance.
Table image
var query = from kur in kurToplamlist
where kur.KurToplamMiktarGetSet > 0
join cariBilg in db.TBLP1CARIs
on kur.CariIdGetSet equals cariBilg.ID
select new
{
cariBilg.ID,
EUROBAKIYE = cariBilg.HESAPADI,
cariBilg.K_FIRMAADI,
cariBilg.K_YETKILIADI,
cariBilg.K_FIRMATELEFON,
cariBilg.K_YETKILITELEFON,
AUDBAKIYE = cariBilg.B_CEPTELEFON,
TLBAKIYE = String.Concat(kur.KurToplamMiktarGetSet.ToString(), kur.DovizTuruGetSet.ToString()),
};
var dfg = from qre in query
select qre.TLBAKIYE;
var aq = (from qw in query
select new {
qw.ID,
EUROBAKIYE = qw.EUROBAKIYE,
qw.K_FIRMAADI,
qw.K_YETKILIADI,
qw.K_FIRMATELEFON,
qw.K_YETKILITELEFON,
AUDBAKIYE = qw.AUDBAKIYE,
TLBAKIYE = String.Join(",", (from qre in query
where qre.ID == qw.ID
select qre.TLBAKIYE).Distinct())
}).Distinct();
return aq;
This is my answer.

Linq : select value in a datatable column

How do you use LINQ (C#) to select the value in a particular column for a particular row in a datatable. The equivalent SQL would be:
select NAME from TABLE where ID = 0
Thanks for your answers. I didn't understand what type of object "MyTable" was (in your answers) and the following code gave me the error shown below.
DataTable dt = ds.Tables[0];
var name = from r in dt
where r.ID == 0
select r.Name;
Could not find an implementation of the query pattern for source type
'System.Data.DataTable'. 'Where' not found
So I continued my googling and found something that does work:
var rowColl = ds.Tables[0].AsEnumerable();
string name = (from r in rowColl
where r.Field<int>("ID") == 0
select r.Field<string>("NAME")).First<string>();
What do you think?
var name = from r in MyTable
where r.ID == 0
select r.Name;
If the row is unique then you could even just do:
var row = DataContext.MyTable.SingleOrDefault(r => r.ID == 0);
var name = row != null ? row.Name : String.Empty;
I notice others have given the non-lambda syntax so just to have this complete I'll put in the lambda syntax equivalent:
Non-lambda (as per James's post):
var name = from i in DataContext.MyTable
where i.ID == 0
select i.Name
Equivalent lambda syntax:
var name = DataContext.MyTable.Where(i => i.ID == 0)
.Select(i => new { Name = i.Name });
There's not really much practical difference, just personal opinion on which you prefer.
If the return value is string and you need to search by Id you can use:
string name = datatable.AsEnumerable().Where(row => Convert.ToInt32(row["Id"]) == Id).Select(row => row.Field<string>("name")).ToString();
or using generic variable:
var name = datatable.AsEnumerable().Where(row => Convert.ToInt32(row["Id"]) == Id).Select(row => row.Field<string>("name"));
var name = from DataRow dr in tblClassCode.Rows where (long)dr["ID"] == Convert.ToInt32(i) select (int)dr["Name"]).FirstOrDefault().ToString()
var x = from row in table
where row.ID == 0
select row
Supposing you have a DataTable that knows about the rows, other wise you'll need to use the row index:
where row[rowNumber] == 0
In this instance you'd also want to use the select to place the row data into an anonymous class or a preprepared class (if you want to pass it to another method)
Use linq and set the data table as Enumerable and select the fields from the data table field that matches what you are looking for.
Example
I want to get the currency Id and currency Name from the currency table where currency is local currency, and assign the currency id and name to a text boxes on the form:
DataTable dt = curData.loadCurrency();
var curId = from c in dt.AsEnumerable()
where c.Field<bool>("LocalCurrency") == true
select c.Field<int>("CURID");
foreach (int cid in curId)
{
txtCURID.Text = cid.ToString();
}
var curName = from c in dt.AsEnumerable()
where c.Field<bool>("LocalCurrency") == true
select c.Field<string>("CurName");
foreach (string cName in curName)
{
txtCurrency.Text = cName.ToString();
}

Categories