Linq not in select on datatable - c#

Hi i've got 2 data tables (bannedlist,countrylist), both contains list of country names and cods in columns cc and country. I am trying to do a query where i can select countries from countrylist table that are not in bannedlist table in order to create a 3rd table.
Any ideas?
I haven't got too far with this.
var ccList = ds.Tables[2].AsEnumerable();
var bannedCCList = ds.Tables[1].AsEnumerable();
var query = from r in ccList....
..
after trying
var bannedCCList = ds.Tables[1].AsEnumerable();
var query = from r in ccList where !bannedCCList.Any(b => b["cc"] == r["cc"])select r;
i still get same country list. banned ones haven't been removed. here is more detail in order to explain more. not sure what i am doing wrong
protected void BindCountryBan(string subd)
{
DataSet ds = new DataSet();
ds = new DB().CountryBan_GetSiteSettings();
BannedCountryListBox.DataSource = ds.Tables[1];
BannedCountryListBox.DataValueField = "cc";
BannedCountryListBox.DataTextField = "country";
BannedCountryListBox.DataBind();
//bind country list
var ccList = ds.Tables[2].AsEnumerable();
var bannedCCList = ds.Tables[1].AsEnumerable();
var query = from r in ccList where !bannedCCList.Any(b => b["cc"] == r["cc"])select r;
//var query = ccList.Except(bannedCCList);
//CountryListBox.DataSource = ds.Tables[2];
DataTable boundTable = query.CopyToDataTable<DataRow>();
CountryListBox.DataSource = boundTable;
CountryListBox.DataValueField = "cc";
CountryListBox.DataTextField = "country";
CountryListBox.DataBind();
}

Except would work if you use it on sequences of the countries:
using System.Linq;
...
var ccList = from c in ds.Tables[2].AsEnumerable()
select c.Field<string>("Country");
var bannedCCList = from c in ds.Tables[1].AsEnumerable()
select c.Field<string>("Country");
var exceptBanned = ccList.Except(bannedCCList);
If you need the full rows where the countries aren't banned, you could try a left outer join:
var ccList = ds.Tables[2].AsEnumerable();
var bannedCCList = ds.Tables[1].AsEnumerable();
var exceptBanned = from c in ccList
join b in bannedCCList
on c.Field<string>("Country") equals b.Field<string>("Country") into j
from x in j.DefaultIfEmpty()
where x == null
select c;

You can use the Except() LINQ extension method like this:
var result = full.Except(banned);
However this will work fine with the default comparer of the contained type. Thus if you want to use a specific column like in your example, you might need another approach like:
from r in ccList
where !bannedCCList.Any(b => b["cc"] == r["cc"])
select r;
Using Except() implies the references are the same in both collections, which I think is not the case with Tables, or correct me if I'm wrong.

Try this:
var query = ccList.Except(bannedCCList);

Related

GridView Only populating 1 result

I'm currently working to add Data to a GridView. The data comes from 2 tables that are on different databases. Currently I am able to populate the first entry, but it does not populate past that. here is the code:
void FillOrder(int inv)
{
var _ord = new OrdersContext();
var _pro = new ProductContext();
var qryOrder = (from o in _ord.OrderDetails
where o.InvNumberId == inv
select new
{
o.ProductID,
o.Quantity
}).ToList();
foreach (var order in qryOrder)
{
int prodID = order.ProductID;
int itemCount = qryOrder.Count;
var qryProducts = (from p in _pro.Products
where p.ProductID == prodID
select new
{
p.ProductID,
p.ProductName
}).ToList();
var results = (from t in qryOrder
join s in qryProducts
on t.ProductID equals prodID
select new
{
t.ProductID,
t.Quantity,
s.ProductName
}).ToList();
OrderItemList.DataSource = results;
OrderItemList.DataBind();
}
}
Can anyone help as to why it's only populating the first entry?
If the number of products involved is relatively small, (and since this query seems to be relate to one invoice, I would think that is true), then you can probably use something like the code below.
This is removing the loop, but the contains method will probably generate a SQL statement something like select ProductID, ProductName from products where productID in (,,,,,,) so may fail if the number of parameters is extremely large.
var _ord = new OrdersContext();
var _pro = new ProductContext();
var qryOrder = (from o in _ord.OrderDetails
where o.InvNumberId == inv
select new
{
o.ProductID,
o.Quantity
}).ToList();
// Get the productIDs
var productIDS = qryOrder.Select(o=>o.ProductID).Distinct().ToList();
// Get the details of the products used.
var qryProducts = (from p in _pro.Products
where productIDS.Contains(p.ProductID)
select new
{
p.ProductID,
p.ProductName
}).ToList();
// Combine the two in memory lists
var results = (from t in qryOrder
join s in qryProducts
on t.ProductID equals s.ProductID
select new
{
t.ProductID,
t.Quantity,
s.ProductName
}).ToList();
OrderItemList.DataSource = results;
OrderItemList.DataBind();

C# LINQ: Get count for each row

Here the query for retrieving all the comptes in my base.
I would like to add a number within the object GridCompte in order to count the element inside the list (1,2,3...):
var comptes = (from c in Comptes
join s in Societies on c.IdSoc equals s.IdSoc
select new GridCompte
{
SocCompteId = c.IdCompte,
Name = c.Name,
Nb = ??? COUNT ???,
.....
SocName = s.Name
}).ToList();
I tried using the group statement, but i didn't manage to achieve my goal.
Any suggestions?
First prepare your linq only for the fields you want to get
var comptes = from c in Comptes
join s in Societies on c.IdSoc equals s.IdSoc
select new
{
SocCompteId = c.IdCompte,
Name = c.Name,
.....
SocName = s.Name
};
Now use index option that is available in Select
var finalComptes = (comptes.AsEnumerable()
.Select((comptes, index) => new GridCompte()
{
SocCompteId = c.IdCompte,
Name = c.Name,
Nb = index + 1,
.....
SocName = s.Name
}).ToList();

Count in select query of Linq to SQL

I am trying to convert below SQL query into Linq.
select eg.userid, eg.groupid, count(r.RID) as RecipientCount
from eg
join g on eg.groupid = g.groupid
join r on g.RID = r.RID
where eg.UserId = '7F813844-3B93-418E-8141-654082C4E37D'
and eg.IsDeleted = 0
and r.Isdeleted = 0
group by eg.groupid
Above query runs properly in SQL.
My Linq code is:
var v = from eml in dc.egs
join recpingroup in dc.g on eml.GroupID equals recpingroup.GroupID
where eml.aspnet_User.LoweredUserName.Equals(strUserName.ToLower())
&& !eml.IsDeleted
&& !recpingroup.r.IsDeleted
select new Info()
{
CreateDt = eml.CreateDt.ToShortDateString(),
UserId = eml.UserId.ToString(),
LastUpdateDt = eml.LastUpdateDt.ToShortDateString(),
Username = eml.aspnet_User.UserName,
GroupDescription = eml.GroupDescription,
GroupID = eml.GroupID.ToString().ToUpper(),
GroupName = eml.GroupName,
Count = dc.g.Count(r1 => r1.GroupID.Equals(eml.GroupID) && !r1.r.IsDeleted)
};
where dc is my DataContext.
But I am having problems in the last property i.e. Count is coming wrong. I want the counts of recipients from recpingroup.r as RecipientCount.
Also note that tables are linked in SQL internally by PK and FK references.
try following
Count = (from x in dc.g where(r1 => r1.GroupID.Equals(eml.GroupID) && !r1.r.IsDeleted) select x.g).count()

Assign Distinct Object/Class in Linq to objects

I am doing following and it works:
var resultsHeader = (from r in o select new {
OrderID = r.OrderID,
subtotal = r.SubTotal,
city = r.orderAddress.BilltoCity
}).Distinct().ToList();
Look at the city = r.orderAddress.BilltoCity Line, is there any way i can populate the entire object there...like this
var resultsHeader = (from r in o select new {
OrderID = r.OrderID,
subtotal = r.SubTotal,
Address = r.orderAddress
}).Distinct().ToList();
Basicly, I want to store entire OrderAddress Object into Address property, however it does not come out as Distinct object.
You can either use DistinctBy from moreLINQ:
var resultsHeader = (from r in o select new {
OrderID = r.OrderID,
subtotal = r.SubTotal,
city = r.orderAddress.BilltoCity
}).DistinctBy(x => new { x.OrderID, x.subtotal }).ToList();
or GroupBy, which is part of LINQ already:
var resultsHeader = (from r in o
group r by new { r.OrderIs, r.SubTotal } into g
select new {
g.Key.OrderID,
g.Key.SubTotal,
Address = g.First().orderAddress
}).ToList()
UPDATE
Or, you can implement Equals and GetHashCode on your Address class and use Distinct as you do now.

Linq Query for dataset in c#?

I have dataset which contains two tables like this:
DataTable dtFields = new DataTable("tmpFieldTable");
dtFields.Columns.Add("FieldID");
dtFields.Columns.Add("CDGroupID");
dtFields.Columns.Add("CDCaption");
dtFields.Columns.Add("fldIndex");
DataTable dtCDGroup = new DataTable("tmpCDGroup");
dtCDGroup.Columns.Add("CDGroupID");
dtCDGroup.Columns.Add("Name");
dtCDGroup.Columns.Add("Priority");
DataSet ds = new DataSet("tmpFieldSet");
ds.Tables.Add(dtFields);
ds.Tables.Add(dtCDGroup);
How can I write following SQL query to LINQ
queryString = "Select FieldID, tmpCDGroup.Name, CDCaption, IIF(ISNULL(Priority),99,Priority), fldIndex from tmpFieldList LEFT OUTER JOIN tmpCDGroup ON tmpFieldList.CDGroupID = tmpCDGroup.CDGroupID order by 4,5 ";
I'm not sure why you're ordering by "4,5", but it would be like this:
var resultArray = tmpFieldList.Join(
tmpCDGroup, // inner join collection
fieldList => fieldList.CDGroupID, // outer key selector
cd => cd.CDGroupID, // inner key selector
(fieldList, cd) => new { // result selector
FieldID = fieldList.FieldID,
Name = cd.Name,
CDCaption = cd.CDCaption,
Priority = fieldList.Priority ?? 99,
fldIndex = fieldList.fldIndex
})
.OrderBy(result => result.Priority)
.ThenBy(result => result.fldIndex)
.ToArray();
Then you can access using, for example,
resultArray[0].FieldID
, etc.
This might work or at least help to get it working. Note that i've changed the type of some columns.
var result = from field in dtFields.AsEnumerable()
join cdGroup in dtCDGroup.AsEnumerable()
on field.Field<int>("CDGroupID") equals cdGroup.Field<int>("CDGroupID")
into fieldGroup
from row in fieldGroup.DefaultIfEmpty()
let priority = row.IsNull("Priority") ? 99 : row.Field<int>("Priority")
orderby priority, row.Field<int>("fldIndex")
select new
{
FieldID = row.Field<int>("FieldID"),
GroupName = row.Field<int>("Name"),
CDCaption = row.Field<int>("CDCaption"),
Priority = priority,
fldIndex = row.Field<int>("fldIndex")
};

Categories

Resources