How to solve this in LINQ query? - asp.net-mvc-3

I was working on MVC3 project. I need help writting Linq expression. My model is something like this.
Model Class
public int Id { get; set; }
public int DetCount { get; set; }
I need to do something like this,
DetCount = (from sel in db.PoDetails where sel.PoId == Id select sel).Count(); // Id is current model Id.
Based on the parent table Id, i need to get the child table records count.
Example
Parent Table
Id Name
1 XYZ
2 ABC
Child Table
Id P_Id
1 1
2 1
3 2
DetCount = (from sel in db.child where sel.P_Id == Id select sel).Count(); // if Id= 1
Result
DetCount = 2;
I have written the code something like this.
Code
model = ...
select new porders
{
Id = p.Id, //This Id is passed to next statement for DetCount.
DetCount = (from sel in db.PoDetails where sel.PoId == Id select sel).Count(); // I need to pass value from another linq query.
}
Please help me for this.
Thanks,

var result = select new porders
{
Id = p.Id,
PODate = p.Date.Value,
RefNo = p.RefNo,
Status = resloc.Description,
Supplier = resstat.Name,
DetCount = db.PoDetails
.Select(p => p.sel)
.Where(sel.PoId == asd.Id).Count()
}

Is it just the count you want? If so this should work:
var DetCount = db.PoDetails.Where(sel=>sel.PoId == Id).Count(); // Id is current model Id.
Cheers :)

Related

How would one create summary columns in query results using Linq-to-SQL?

Let's say we have these tables:
CAR
ID Name
1 Mustang
2 Taurus
CAR_PART
ID CAR_ID PART_NUMBER
1 1 M772
2 1 A443
3 2 Z889
CAR_COLOR
ID CAR_ID COLOR_NAME
1 1 Red
2 1 Blue
3 2 Yellow
We need to use Linq-to-SQL to get this result:
CAR_ID CAR_NAME CAR_PART_LIST CAR_COLOR_LIST
1 Mustang M772,A443 Red,Blue
How would this be accomplished? I have a new class created with the result column names, and figure a select new MyClass{}; at the end would be good, but am not sure how to handle the multiple groupings for the CAR_PART_LIST and CAR_COLOR_LIST columns.
Any ideas?
edit: here is what I have so far:
from car in db.CAR
join part in db.CAR_PART on car.ID equals part.CAR_ID
join color in db.CAR_COLOR on car.ID equals color.CAR_ID
where car.ID = 1
select new MySearchResult{
CAR_ID = car.ID,
CAR_NAME = car.Name,
CAR_PART_LIST = ?,
CAR_COLOR_LIST = ?
}
public class MySearchResult{
public int CAR_ID { get; set; }
public string CAR_NAME { get; set; }
public string CAR_PART_LIST { get; set; }
public string CAR_COLOR_LIST { get; set; }
public MySearchResult() { }
}
Using the obvious String extension method:
public static string Join(this IEnumerable<string> s, string sep) => String.Join(s, sep);
You can compute the answer by using group join on each related table:
var ans = from car in db.CAR
join part in db.CAR_PART on car.ID equals part.CAR_ID into partj
join color in db.CAR_COLOR on car.ID equals color.CAR_ID into colorj
where car.ID == 1
select new MySearchResult {
CAR_ID = car.ID,
CAR_NAME = car.Name,
CAR_PART_LIST = partj.Select(p => p.PART_NUMBER).Join(","),
CAR_COLOR_LIST = colorj.Select(c => c.COLOR_NAME).Join(",")
};
Do you have foreign keys set up for db.CAR_PART and db.CAR_COLOR? If so, that linq-to-sql will automatically give you properties for the joins. So, it becomes:
var q = from car in db.Car
where car.ID == 1
select new MySearchResult
{
CAR_ID = car.ID,
CAR_NAME = car.Name,
CAR_PART_LIST = String.Join(",", car.CAR_PARTs.Select(cp=>cp.PART_NUMBER))
CAR_PART_LIST = String.Join(",", car.CAR_COLORs.Select(cp=>cp.COLOR_NAME))
};
So you have a table of CarParts, where every CarPart has a CarId and a PartNumber; and you have a table of CarColours, where every CarColour has a Carid and a ColourName.
I assume you do not support invisible cars, so every car has at least one part, and one colour.
You want a sequence of all CarIds, each CarId with the CarName, a list of all CarParts belonging to this CarId(= that have this CarId as foreign key) and a list of all ColourNames belonging to this CarId (again using the foreign key.
To do this, first we get all CarIds with their CarParts and all CarIds with their ColourNames, then we can Join the results on common CarId.
If you think there might be cars without parts or without colours, you need to do a 'Full outer Join' instead of a normal Join. This is not part of standard LINQ, but you can write the extension function yourself. See LINQ Full Outer Join
After the join on common CarId, we Join the result with your Cars on CarId
var partsGroupedByCarId = carParts.GroupBy( // make groups of carParts
carPart => carPart.CarId); // with common CarId as Key
var coloursGroupedByCarId = carColours.GroupBy( // make groups of carColours
carColour => carColour.CarId);, // with common CarId as Key
var joinResult = partsGroupedByCarId.Join( // Join the two groups
coloursGroupedByCarId,
partGroup => partGroup.Key, // from each group of parts take the key (= CarId)
colourGroup => // from each group of colours take the key (= CarId)
(partGroup, colourGroup) => new // when they match make a new object
{
CarId = partGroup.Key, // with the common CarId
CarParts = partGroup // all partNumbers of the car with CarId
.Select(item => item.PartNumber),
CarColours = colourGroup // all colourNames of the car with carId
.Select(item => item.ColourName),
});
Finally a Join of the Cars with all their Colours and Parts:
var result = Cars.Join(joinResult, // Join all cars with the joinResult
car => Id, // from every car take the id
joinedItem => joinedItem.CarId, // from every joinedItem take the CarId
(car, joinedItem) => new // for every car with its matching joinedItem
{ // make a new object
Id = car.Id,
Name = car.Name,
Parts = joinedItem.CarParts.ToList(),
Colours = joinedItem.CarColours.ToList(),
});
TODO: consider creating one big LINQ statements. As all statements use deferred execution I don't think this will improve efficiency. It certainly will decrease readability.
I writed it here dotnetfiddle please check it out:
var q = from car in cars
join part in carparts on car.ID equals part.CAR_ID into parts
join color in carcolors on car.ID equals color.CAR_ID into clrs
where car.ID == 1
select new MySearchResult{
CAR_ID = car.ID,
CAR_NAME = car.Name,
CAR_PART_LIST = String.Join(",",parts.Select(p => p.PART_NUMBER)),
CAR_COLOR_LIST = String.Join(",",clrs.Select(c => c.COLOR_NAME))};
foreach (var item in q)
Console.WriteLine("{0} {1} {2} {3}",
item.CAR_ID,
item.CAR_NAME,
item.CAR_PART_LIST,
item.CAR_COLOR_LIST);

LINQ perform select and insert in single query

I am working on Entity Framework 6 in C# .NET CORE 2.0 application. I have requirement to get role id from database where roleName = x and add role reference to user as in one: many table
I want to avoid 2 trip to database, I want to do in one go or in single Linq query
UserDataModel userObj = new UserDataModel()
{
Id = fakeUserID,
Name = "k1",
Surname = "z",
Email = "k.z#yahoo.co.uk",
Roles = new List<UserRoleDataModel>
{
new UserRoleDataModel {
UserId = fakeUserID,
RoleId = Context.Roles.Where(roleName => roleName.Name == RoleName).Select(x=>x.Id)
}
}
};
Context.Add<UserModel>(userObj);
Context.SaveChanges();
above code gives me error at RoleId
refer in screen shot;
Error because you are assigning IQueryable to a Property of type Int (I Assumed its Int). You should do this:
RoleId = Context.Roles.Where(roleName => roleName.Name == RoleName && roleName.Id==Id).Select(x=>x.Id).First();

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

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

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()
};

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