get list from a class to fill taxtbox in other class by linq - 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);

Related

How to order items within the group of anonymous type?

I would like to get a result of Linq query as groups of anonymous objects. The items within the groups should be ordered by ID field. I can reach this partly by lambda syntax, but can't get an anonymous objects as result. So I need part of each example.
Executable code: https://dotnetfiddle.net/cPJUN9
var res_g = (from dg in list
group new { dg.ID, dg.IDOperation, dg.IDDiagnosis } by dg.IDOperation
into dg_group
select dg_group);
lambda syntax
var res_g = list
.GroupBy(x => x.IDOperation)
.Select(x => x.OrderBy(x => x.ID)); // order dg by ID asc within group
Alas, you didn't describe exactly your requirements where, only that you want some anonymous type and that they should be ordered by Id. Your query syntax makes different groups than your method syntax. So I can only give an example to create your sequence of anonymous objects
So you have a sequence of similar items, where every item has at least properties Id and IdOperation. You want to make groups of items where every item in each group has the same value for IdOperation. You want to order the elements in each group by ascending Id, and create some anonymous type.
You didn't specify what you want in your anonymous object (after all: your code doesn't do what you want, so I can't deduct it from your code)
Whenever I use GroupBy, and I want to specify the elements of each group, I use the overload of GroupBy that has a parameter resultSelector. With the resultSelector I can precisely define the elements of the group. (The link refers to IQueryable, there is also an IEnumerable version)
IEnumerable<Operations> operations = ... // = your list
// Make Groups of Operations that have the same value for IdOperation
var result = operations.GroupBy(operation => operation.IdOperation,
// parameter resultSelector: take the key (=idOperation) and all Operations that have
// this idOperation, to make one new.
(idOperation, operationsWithThisId) => new
{
// do you need the common idOperation?
IdOperation = idOperation,
// Order the elements in each group by Id:
Operations = operationsWithThisId.OrderBy(operation => operation.Id)
.Select(operation => new
{
// Select only the operation properties that you plan to use
Id = operation.Id,
Name = operation.Name,
StartDate = operation.StartDate,
...
})
.ToList(),
});
In words: from your sequence of Operations, make groups of Operations that have the same value for IdOperation. Then take this common IdOperation, and all Operations that are in this group, to make one anonymous object: this is the anonymous object that you were talking about. So per group, you make one anonymous object.
IdOperation is the value that all Operations in this group have in common
Operations is a list. All Operations in this group are ordered by ascending Id. Several properties are Selected and the result is put in a List.
If you want to group differently, like in you query syntax, simply change parameter keySelector:
var result = operations.GroupBy(operation => new
{
Id = operation.ID,
IdOperation = operation.IDOperation,
IdDiagnosis = operation.IDDiagnosis
},
Although this corresponds with what you did in your query syntax, you will have groups of Operations that have same value for Id / IdOperation / IDDiagnosis. It will be useless to sort the elements in the group by Id, because all Ids in this group will be equal.
Conclusion
With parameter resultSelector you can define the result exactly as you want: the result is not an IEnumerable<IGrouping<Tkey, TElement>>, but an IEnumerable<TResult>.
The TResult is one object created from all elements in one group and the common group value.
you can update GetDict function inner loop to use orderby on group elements
public static void GetDict(List<Operation> list)
{
var res_g = (from dg in list
group new { dg.ID, dg.IDOperation, dg.IDDiagnosis } by dg.IDOperation
into dg_group
select dg_group);
foreach (var x in res_g)
{
Console.WriteLine("Key: " + x.Key);
foreach (var y in x.OrderBy(o=>o.ID))
{
Console.WriteLine("{0} {1} {2}", y.ID, y.IDOperation, y.IDDiagnosis); ;
}
}
}
I hope this solve the issue.
Depending on your Requirements EDIT but I'm Tuning the result set
var res_g_2 = list.Select( p=> new { p.ID, p.IDOperation, p.IDDiagnosis }) .GroupBy(g => g.IDOperation)
.Select(g => new {
IDOperation = g.Key,
Records = g.OrderBy(group => group.ID)
});
Edit full version
public static void GetDict(List<Operation> list)
{
var res_g = (from dg in list
group new { dg.ID, dg.IDOperation, dg.IDDiagnosis } by dg.IDOperation
into dg_group
select new
{
Key = dg_group.Key,
Records = dg_group.OrderBy(g => g.ID)
}) ;
var res_g_2 = list.Select( p=> new { p.ID, p.IDOperation, p.IDDiagnosis }) .GroupBy(g => g.IDOperation)
.Select(g => new {
Key = g.Key,
Records = g.OrderBy(group => group.ID)
});
// you can use either res_g or res_g_2 both give the same results
foreach (var x in res_g)
{
Console.WriteLine("Key: " + x.Key);
foreach (var y in x.Records)
{
Console.WriteLine("{0} {1} {2}", y.ID, y.IDOperation, y.IDDiagnosis); ;
}
}
}

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 with Include and many-to-many

I have rather specific requirement for my Linq statement. I've looked through dozens of examples, but could't find satisfying answer.
I have a collection of courses, which holds collection of groups, which holds collection of members. My goal is to create linq statement for IQuerable which returns a collection of courses that user belongs to, and includes collection of groups within each course that user belongs to if there is any.
I did manage to build a linq statement which returns what I wanted but filters out all of the courses that don't have any groups that user belongs to inside them:
var courses2 = (from c in _set
from s in c.Students
where (s.UserName == userName)
from g in c.Groups
from m in g.Members
where (m.UserName == userName)
select c)
.Include(c => c.Groups)
.OrderBy(c => c.Title)
How could I change it to include those as well?
Assuming your student entity has a nav property to entity Class for class membership, and Class entities have a nav property Groups to the Group entity, which in turn have a nav property to Students:
// get the students to query against
var students = db.Students.Where( s => s.UserName == userName );
// get classes per group
var classesViaGroups =
students.SelectMany( s => s.Groups )
.SelectMany( g =>
g.Classes.Select( c =>
new { GroupName = g.Name, ClassObj = g.Class } ) );
// get classes by the student entities alone
var classesViaStudents =
students.SelectMany( s => s.Classes )
.Select( c => new { GroupName = null, ClassObj = c } );
You can then do what you will with classesViaGroups and classesViaStudents - combine them, build a lookup or dictionary by group or class, etc.

Linq to Entities, Take(3) from Joined table

I am trying to populate a ViewModel in an MVC app with data from a parent table joined with a child table. The only data I want from the child table is a comma diliminated string from the Nomenclature field of the top three records and put them into a string field in the ViewModel. Here is what I have tried without success:
public IEnumerable<ReqHeaderVM> GetOpenReqs(string siteCode)
{
var openReqs = from h in context.ReqHeaders
join l in context.ReqLineItems on h.ID equals l.ReqID into reqLineItems
select new ReqHeaderVM
{
ReqID = h.ID,
ShopCode = h.ShopCode
Nomenclatures = reqLineItems.Select(x => x.Nomenclature).Take(3) // This doesn't work
};
return (openReqs.ToList());
}
Here is the ViewMdel:
public class ReqHeaderVM
{
[Editable(false)]
public string ReqID { get; set; }
public string ShopCode { get; set; }
public string Nomenclatures {get; set;}
}
Assuming that you have proper relationship (foreign key) between ReqHeaders and ReqLineItems, this should give you what you are looking for...
public IEnumerable<ReqHeaderVM> GetOpenReqs(string siteCode)
{
var openReqs = from h in context.ReqHeaders
select new
{
ReqID = h.ID,
ShopCode = h.ShopCode
Nomenclatures = h.ReqLineItems
.OrderBy(x => x.SomeColumn)
.Select(x => x.Nomenclature)
.Take(3)
};
var openReqsTran = from oreq in openReqs.AsEnumerable()
select new ReqHeaderVM
{
oreq.ReqID,
oreq.ShopCode,
Nomenclatures = string.Join(", ", oreq.Nomenclatures)
};
return (openReqsTran);
}
Note that Nomenclatures is a list of type of Nomenclature.
Yes, the join creates a single Cartesian result set. (think tabular data) what you are attempting to do. To get the results you want you have a few choices.
use lazy loading and iterate over each header querying the line items individually.
pro - simple queries
con - select n+1
query all headers and all line items, but build view model with only the top 3
pro - single query
con - large Cartesian result set query too much data
query all headers and all associated lines individuals
pro - 2 smaller, simpler queries
con - query too many line details.
query all headers and top 3 lines per header in 2 queries
pro - get only the information you require
con - complex query for top 3 lines per header.

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).

Resources