How do you filter a list based on matching items in another list? - linq

I have an Organisation object
public class Organisation
{
OrgId {get....}
OrgName {get...}
AccountTypes { get....} //this is of type List<AccountType>
}
and an AccountType object
public class AccountType
{
AccountTypeId {get....}
AccountTypeName {get...}
}
I'm looking for a way to look through the existing Organisations List and remove AccountTypes from each organisation where the account types are not found in another list of AccountTypes (which would be a post back from a browser).
Would I do something like?
var foundOrgs = from org in orgs
where org.OrganisationId == Convert.ToInt32(hash["orgId"])
select org;
Organisation organisation = foundOrgs.ElementAt(0);
organisation.AccountTypes.Clear();
organisation.AccountTypes = // What goes here?
I'm looking to do a Linq query that will compare one list with another and return only those items where the AccountTypeIDs match, or are present.

You can use List<T>.RemoveAll:
// where accounts is IEnumerable<int>
organisation.AccountTypes.RemoveAll(at => !accounts.Contains(at.AccountTypeId));

EDITED CODE
//created account id list over here
var AccountTypeID = accountType.Select(x=>x. AccountTypeId);
//you code
var foundOrgs = from org in orgs
where org.OrganisationId == Convert.ToInt32(hash["orgId"])
select org;
Organisation organisation = foundOrgs.ElementAt(0);
organisation.AccountTypes.Clear();
//changes in code where you want to change -// What goes here?
List<AccountTypes> templist = organisation.AccountTypes;
organisation.AccountTypes =
from acc in templist
where !AccountTypeID.Conains(acc.AccountTypeId)
select acc).ToList();
EDIT
No sure but you can try out
var orgdata= from org in foundOrgs
select { OrgId =org.OrgId ,OrgName = org.OrgName ,
AccountTypes = ( from acc in org.AccountTypes
where !AccountTypeID.Conains(acc.AccountTypeId)
select acc) };
Try something like this
var ids = {1, 2, 3};
var query = from item in context.items
where !ids.Contains( item.id )
select item;
this will give you list of element which are not part of 1,2,3 i.e ids list , same you can apply in you code first find out which are not there and than remove it from the list
Image

Related

get list from a class to fill taxtbox in other class by linq

how to get just special 2 attributes from a table to other table( and placement in related textbox) by LINQ??
public string srcht(ACTIVITIES sn)
{
db db = new db();
var q = (from i in db.costumers.Where(i => i.id== sn.id)select i.name).ToList();
return q.Single();
}
public string srcht(ACTIVITIES sn)
{
db db = new db();
var q = (from i in db.costumers.Where(i => i.id== sn.id)select i.family).ToList();
return q.Single();
}
i did linq twice to fill 2 textboxes by name and family in other table. can i do it by one LINQ?
So you have an Activity in sn, and you want the Name and the Family of all Customers that have an Id equal to sn.Id.
var result = db.Customers.Where(customer => customer.Id == sn.Id)
.Select(customer => new
{
Name = customer.Name,
Family = customer.Family,
});
In words: in the database, from the table of Customers, keep only those Customers that have a value for property Id that equals the value of sn.Id. From the remaining Customers select the values of Name and Family.
If you expect that there will only be at utmost one such customer (so if Id is the primary key), just add:
.FirstOrDefault();
If you think there will be several of these customers, add:
.ToList();
The result will be an object, or a list of objects of some anonymous type with two properties: Name and Family.
If you want to mix the Name and the Family in one sequence of strings, which I doubt, consider to put the Name and the Family in an array. Result is sequence of arrays of strings. To make it one array of Strings, use SelectMany:
var result = db.Customers
.Where(customer => customer.Id == sn.Id)
.Select(customer => new string[]
{
customer.Name,
customer.Family,
})
.SelectMany(customer => customer);

Linq to Objects - Left Outer Join Distinct Object Property Values to an Aggregate Count

Lets say I have a generic list of the the following objects:
public class Supermarket
{
public string Brand { get; set; }
public string Suburb { get; set; }
public string State { get; set; }
public string Country { get; set; }
}
So using a List<Supermarket> which is populated with many of these objects with different values I am trying to:
Select the distinct Suburb properties from a
superset of Supermarket objects contained in a List<Supermarket> (say this superset contains 20
distinct Suburbs).
Join the Distinct List of Suburbs above to another set of aggregated and counted Suburbs obtained by a LINQ query to a different, smaller list of List<Supermarket>
The distinct items in my superset are:
"Blackheath"
"Ramsgate"
"Penrith"
"Vaucluse"
"Newtown"
And the results of my aggregate query are:
"Blackheath", 50
"Ramsgate", 30
"Penrith", 10
I want to join them to get
"Blackheath", 50
"Ramsgate", 30
"Penrith", 10
"Vaucluse", 0
"Newtown", 0
Here is what I have tried so far:
var results = from distinctSuburb in AllSupermarkets.Select(x => x.Suburb).Distinct()
select new
{
Suburb = distinctSuburb,
Count = (from item in SomeSupermarkets
group item by item.Suburb into aggr
select new
{
Suburb = aggr.Key,
Count = aggr.Count()
} into merge
where distinctSuburb == merge.Suburb
select merge.Count).DefaultIfEmpty(0)
} into final
select final;
This is the first time I have had to post on Stack Overflow as its such a great resource, but I can't seem to cobble together a solution for this.
Thanks for your time
EDIT: OK So I solved this a short while after the initial post. The only thing I was missing was chaining a call to .ElementAtOrDefault(0) after the call to .DefaultIfEmpty(0). I also verifed that using .First() instead of .DefaultIfEmpty(0) as Ani pointed out worked, The correct query is as follows:
var results = from distinctSuburb in AllSupermarkets.Select(x => x.Suburb).Distinct()
select new
{
Suburb = distinctSuburb,
Count = (from item in SomeSupermarkets
group item by item.Suburb into aggr
select new
{
Suburb = aggr.Key,
Count = aggr.Count()
} into merge
where distinctSuburb == merge.Suburb
select merge.Count).DefaultIfEmpty(0).ElementAtOrDefault(0)
} into final
select final;
LASTLY: I ran Ani's code snippet and confirmed that it ran successfully, so both approaches work and solve the original question.
I don't really understand the assumed equivalence between State and Suburb (where distinctSuburb == merge.State), but you can fix your query adding a .First() after the DefaultIfEmpty(0) call.
But here's how I would write your query: using a GroupJoin:
var results = from distinctSuburb in AllSupermarkets.Select(x => x.Suburb).Distinct()
join item in SomeSupermarkets
on distinctSuburb equals item.Suburb
into suburbGroup
select new
{
Suburb = distinctSuburb,
Count = suburbGroup.Count()
};

How to declare the result of query in LINQ to Entities

I just started using MS entity framework and have the following problem with LINQ. I will simplify my problem to make it clearer; let's say that I have three tables in SQL Server database:
CustomerData (PK is CustomerId, the table also has some twenty columns to hold customer data).
CustomerData1 (holds some data for the customer in one to one relationship).
CustomerData2 (also holds some data for the customer in one to one relationship).
I know the data with one to one relationship should better be in the same table, but this is some corporate db and it is not possible to alter the original table (so all our data should be in the separate tables).
Now I want to display a list of customer with their data from CustomerData table and add some data columns from CustomerData1 via join.
On the other hand, I want to display a list of customers and add some data from the other table CustomerData2 via join.
So the data is basically the same both times except that in the first case the result includes some columns from CustomerData1 and in the second case some data from CustomerData2 table.
So I created the class Customer with properties for all relevant columns in CustomerData table and added properties for columns that should be included from CustomerData1 and properties that should be included from CustomerData2.
All columns should be included each time, except that when first call will be made the properties that map to CustomerData2 table will be empty and during the second call the properties that map to CustomerData1 table will be empty.
For this I wanted to create one function so I tried to create it like this:
Input parameter in function is whether data from CustomerData1 or CustomerData2 is included.
if (firstList)
{
var query1 = from obj in CustomerData
join rel in CustomerData1
on obj.CustomerId equals rel.CustomerId
select new { obj, rel };
}
if (secondList)
{
var query2 = from obj in CustomerData
join rel in CustomerData2
on obj.CustomerId equals rel.CustomerId
select new { obj, rel };
}
So this code gives me the anonymous type based on the input parameter. Now I want to create Customer objects and order it (order is always the same, it does not depend on input parameter). So I want to create a list of ordered customers and include additional data based on the input parameter.
var query3 = <previous_query_variable>.Select(f => new Customer {
Id = f.obj.CustomerId,
Name = f.obj.CustomerName,
... other columns from Customer table (a lot of them)
//and then add some additional columns based on the input parameter
Data1 = f.rel.someDataFromCustomer1, //only when firstList == true, otherwise empty
Data2 = f.rel.someDataFromCustomer2 //only when secondList == true, otherwise empty
}).OrderBy(f => f.Name); //order by customer name
Of course this does not compile, since both vars are inside if statements. I know I could copy this last statement (var query3 = ...) inside both if statements and include only relevant assignments (Data1 or Data2), but I don't want to assign properties that map to CustomerData table twice (once in both if statements) nor I want to order twice.
How can I solve this problem? I am using .NET 4.
You cannot declare a variable for an anonymous type up-front, i.e. before your two if statements. (Something like var query = null is not supported.) You will have to create a helper type and project into it, like so:
public class ProjectedCustomerData
{
public CustomerData CustomerData { get; set; }
public CustomerData1 CustomerData1 { get; set; }
public CustomerData2 CustomerData2 { get; set; }
}
And then the projection:
IQueryable<ProjectedCustomerData> resultQuery = null;
if (firstList)
{
resultQuery = from obj in CustomerData
join rel in CustomerData1
on obj.CustomerId equals rel.CustomerId
select new ProjectedCustomerData
{
CustomerData = obj,
CustomerData1 = rel
};
}
if (secondList)
{
resultQuery = from obj in CustomerData
join rel in CustomerData2
on obj.CustomerId equals rel.CustomerId
select new ProjectedCustomerData
{
CustomerData = obj,
CustomerData2 = rel
};
}
var query3 = resultQuery.Select(f => new Customer {
Id = f.CustomerData.CustomerId,
Name = f.CustomerData.CustomerName,
// ...
Data1 = f.CustomerData1.someDataFromCustomer1,
Data2 = f.CustomerData2.someDataFromCustomer2
}).OrderBy(f => f.Name);
I am not sure if Customer is an entity in your model or only a class you are using for your projection. If it's an entity you have to change the last code because you cannot project into an entity (basically you would need another helper type for your projection).

Filtering User table by MembershipUserCollection

So, I have ASP Membership set up in my application. I also have a separate User table for managing non-membership related data. During user management I need to make sure that my application queries both tables. I have the below Controller that returns a list of approved users, but it seems like there has to be a simpler way to accomplish this. What is a better way to do it?
QuoteExchangeDB _db = new QuoteExchangeDB();
[MyAuthorize(Roles = "Administrator")]
public ActionResult Admin()
{
MembershipUserCollection agents = Membership.GetAllUsers();
IEnumerable<MembershipUser> unfiltered = agents.Cast<MembershipUser>();
var filtered = unfiltered.Where(u => u.IsApproved);
List<User> users = new List<User>();
foreach (var item in filtered)
{
if (item.IsApproved)
{
Guid guid = (Guid)item.ProviderUserKey;
users.Add(_db.Users.Single(u => u.MembershipGuid.Equals(guid)));
}
}
return View(users);
}
This looks like you probably want a simple join in LINQ.
var filtered = Membership.GetAllUsers().Cast<MembershipUser>().Where(u => u.IsApproved);
var users = from f in filtered
join u in _db.Users on ((Guid)f.ProviderUserKey) equals u.MembershipGuid
select u;
You could probably make one statement out of that even:
var users = from f in Membership.GetAllUsers().Cast<MembershipUser>()
join u in _db.Users on ((Guid)f.ProviderUserKey) equals u.MembershipGuid
where f.IsApproved
select u;
Edit: Given that I'm not sure how joining an IEnumerable with an IQueryable might affect things/cause problems in this instance, here's a blog about doing that.

Subsonic 3 Linq Projection Issue

OK I'm banging my head against a wall with this one ;-)
Given tables in my database called Address, Customer and CustomerType, I want to display combined summary information about the customer so I create a query to join these two tables and retrieve a specified result.
var customers = (from c in tblCustomer.All()
join address in tblAddress.All() on c.Address equals address.AddressId
join type in tblCustomerType.All() on c.CustomerType equals type.CustomerTypeId
select new CustomerSummaryView
{
CustomerName = c.CustomerName,
CustomerType = type.Description,
Postcode = address.Postcode
});
return View(customers);
CustomerSummaryView is a simple POCO
public class CustomerSummaryView
{
public string Postcode { get; set; }
public string CustomerType { get; set; }
public string CustomerName { get; set; }
}
Now for some reason, this doesn't work, I get an IEnumerable list of CustomerSummaryView results, each record has a customer name and a postcode but the customer type field is always null.
I've recreated this problem several times with different database tables, and projected classes.
Anyone any ideas?
I can't repro this issue - here's a test I just tried:
[Fact]
public void Joined_Projection_Should_Return_All_Values() {
var qry = (from c in _db.Customers
join order in _db.Orders on c.CustomerID equals order.CustomerID
join details in _db.OrderDetails on order.OrderID equals details.OrderID
join products in _db.Products on details.ProductID equals products.ProductID
select new CustomerSummaryView
{
CustomerID = c.CustomerID,
OrderID = order.OrderID,
ProductName = products.ProductName
});
Assert.True(qry.Count() > 0);
foreach (var view in qry) {
Assert.False(String.IsNullOrEmpty(view.ProductName));
Assert.True(view.OrderID > 0);
Assert.False(String.IsNullOrEmpty(view.CustomerID));
}
}
This passed perfectly. I'm wondering if you're using a reserved word in there?
This post seems to be referring to a similar issue...
http://groups.google.com/group/subsonicproject/browse_thread/thread/2b569539b7f67a34?hl=en&pli=1
Yes, the reason Rob's example works is because his projection's property names match exactly, whereas John's original example has a difference between CustomerType and type.Description.
This shouldn't have been a problem, but it was - the Projection Mapper was looking for properties of the same name and wasn't mapping a value if it didn't find a match. Therefore, your projection objects' properties would be default values for its type if there wasn't an exact name match.
The good news is, I got the latest source today and built a new Subsonic.Core.dll and the behavior is now fixed.
So John's code above should work as expected.
I just downloaded the latest build from 3/21/2010, which is about 2 months after the last poster on this thread, and the problem still exists in the packaged binary. Bummer.
Here what I have to do:
var data =
(from m in Metric.All()
where m.ParentMetricId == parentId
select new
{
m.MetricName,
m.MetricId,
})
.ToList();
var treeData =
from d in data
select new TreeViewItem
{
Text = d.MetricName,
Value = d.MetricId.ToString(),
LoadOnDemand = true,
Enabled = true,
};
return new JsonResult { Data = treeData };
If I try to do the projection directly from the Subsonic query, the Text property ends up with the ID, and the Value property ends up with the Name. Very strange.

Resources