List Multiple Columns from Different tables - c#

I am creating a list and want to include columns from multiple tables. Here is my code:
var jobAssignments = new List<JobAssignment>
{
new JobAssignment { JobID = jobs.Single (j => j.Status == Status.New, j => j.Priority == Priority.High).JobID,
TechnicianID = technicians.Single(c => c.LastName == "Dion").TechnicianID,
AssignmentDate = DateTime.Parse("2005-09-01")}
I want to display Status and Priority which come from the table "Job"
I also want to display LastName which comes from technician and Assignment date which comes from JobAssignment table.
I assume that the "jobs.Single" is wrong, but what do i replace this with?

Related

Random with condition

I have the following code to extract records from a dbcontext randomly using Guid class:
var CategoryList = {1,5};
var generatedQues = new List<Question>();
//Algorithm 1 :)
if (ColNum > 0)
{
generatedQues = db.Questions
.Where(q => CategoryList.Contains(q.CategoryId))
.OrderBy(q => Guid.NewGuid()).Take(ColNum).ToList();
}
First, I have a list of CategoryId stored in CategoryList as a condition to be fulfilled when getting records from the db. However, I would like to achieve an even distribution among the questions based on the CategoryId.
For example:
If the ColNum is 10, and the CategoryId obtained are {1,5}, I would like to achieve by getting 5 records that are from CategoryId = 1 and another set of 5 records from CategoryId = 5. If the ColNum is an odd number like 11, I would also like to achieve an even distribution as much as possible like maybe getting 5 records from CategoryId 1 and 6 records from CategoryId 2.
How do I do this?
This is a two step process,
Determine how many you want for each category
Select that many items from each category in a random order
For the first part, define a class to represent the category and how many items are required
public class CategoryLookup
{
public CategoryLookup(int catId)
{
this.CategoryId = catId;
}
public int CategoryId
{
get; private set;
}
public int RequiredAmount
{
get; private set;
}
public void Increment()
{
this.RequiredAmount++;
}
}
And then, given your inputs of the required categories and the total number of items required, work out how many are required for each category
var categoryList = new []{1,5};
var colNum = 7;
var categoryLookup = categoryList.Select(x => new CategoryLookup(x)).ToArray();
for(var i = 0;i<colNum;i++){
categoryLookup[i%categoryList.Length].Increment();
}
The second part is really easy, just use a SelectMany to get the list of questions (Ive used a straight linq to objects to test, should work fine for database query. questions in my code would just be db.Questions in yours)
var result = categoryLookup.SelectMany(
c => questions.Where(q => q.CategoryId == c.CategoryId)
.OrderBy(x => Guid.NewGuid())
.Take(c.RequiredAmount)
);
Live example: http://rextester.com/RHF33878
You could try something like this:
var CategoryList = {1,5};
var generatedQues = new List<Question>();
//Algorithm 1 :)
if (ColNum > 0 && CategoryList.Count > 0)
{
var take = // Calculate how many of each
// First category
var query = db.Questions
.Where(q => q.CategoryId == CategoryList[0])
.OrderBy(q => Guid.NewGuid()).Take(take);
// For all remaining categories
for(int i = 1; i < CategoryList.Count; i++)
{
// Calculate how many you want
take = // Calculate how many of each
// Union the questions for that category to query
query = query.Union(
query
.Where(q => q.CategoryId == CategoryList[i])
.OrderBy(q => Guid.NewGuid()).Take(take));
}
// Randomize again and execute query
generatedQues = query.OrderBy(q => Guid.NewGuid()).ToList()
}
The idea is to just get a random list for each category and add them all together. Then you randomize that again and create your list. I do not know if it will do all this on the database or in memory, but it should be database I think. The resulting SQL will look horrible though.

How to filter results in Entity Framework with multiple select box

I have three tables for blog posts:
post_table for posts properties like post_id, post_title and etc.
category_table including of two columns such as category_id and category_name
and post_category_table that is an interface table for relationship between post_table and category_table and it has two foreign key columns such as post_id and category_id.
Note that each post can have one or more categories.
multiple select box (image)
Now I have an multiple select box (like attachment image) for categories that user be able to select one or more categories. When user select one or more categories from select box, results should be limited to selected categories.
How do I write "Where" condition for this problem with Entity Framework?
My code is:
var query = context.post_Table
.Select(postinfo => new {
post_title = postinfo.post_title,
post_date = postinfo.post_date,
post_id=postinfo.post_id,
post_category = postinfo.post_category_table.Select(cc => new {
cc0=cc.category_id,
cc1 = cc.category_table.category_name,
}),
}).Where(???)
You should be able to get a collection of category ids from the multiple selection box (the ids of the selected categories).
Let's call that selectedCategoryIds and let's assume it's an IEnumerable<int>.
To filter the results according to the selected categories you'd do this:
var query = context.post_Table
.Select(postinfo => new
{
post_title = postinfo.post_title,
post_date = postinfo.post_date,
post_id=postinfo.post_id,
post_category = postinfo.post_category_table.Select(cc => new
{
cc0 = cc.category_id,
cc1 = cc.category_table.category_name,
})
})
.Where(info => info.post_category.Any(c => selectedCategoryIds.Contains(c.cc0)));
Edit
If you have some conditional logic you can split and compose the query accordingly:
var query = context.post_Table
.Select(postinfo => new
{
post_title = postinfo.post_title,
post_date = postinfo.post_date,
post_id=postinfo.post_id,
post_category = postinfo.post_category_table.Select(cc => new
{
cc0 = cc.category_id,
cc1 = cc.category_table.category_name,
})
});
if(selectedCategoryIds != null && selectedCategoryIds.Any())
{
query = query.Where(info => info.post_category.Any(c => selectedCategoryIds.Contains(c.cc0)));
}
However if your conditional logic is more complex than the trivial example above please take a look at my answer to a previous question on why you should use a predicate builder.

Retrieving List<> of values for single field in Entity Framework

I have a table called ProjDetails which has all the project details, now I want to retrieve the details of all the projects employee was involved.
Public EmpProject retrieveProjDetails(int empId, int managerId)
{
var projDetails =
{
EmpId = empProject.EmployeeId,
ManagerId = empProject.ManagerId,
List<projectId> =
List<projectName> =
}
})
}
Here the combination of EmployeeId and ManagerId can have multiple records and that means multiple project ids, I need to retrieve those all project ids, and then I need to join with another table Projects and get the names of those projects based on the project Ids.
i think you can do this:
var porjDetails = (from pd in SBDB.ProjDetails
where pd.EmployeeId == empId && pd.ManagerId == managerId
select new EmpProject{
EmpId = pd.EmployeeId,
ManagerId = empProject.ManagerId,
ProjectIds = SBDB.Projects.where(p=>p.ProjectId == pd.ProjectId).Select(p=>p.Id),
ProjectNames = SBDB.Projects.where(p=>p.ProjectId == pd.ProjectId).Select(p=>p.Name)
});
furthermore, i think it's better to have a Projects property, instead of ProjectIds and ProjectNames

How to sort a list after AddRange?

new to C#, SQL and Linq. I have two lists, one "dataTransactions" (fuel from gas stations) and a similar one "dataTransfers" (fuel from slip tanks).
They each access a different table from SQL and get combined later.
List<FuelLightTruckDataSource> data = new List<FuelLightTruckDataSource>();
using (SystemContext ctx = new SystemContext())
{
List<FuelLightTruckDataSource> dataTransactions
= ctx.FuelTransaction
.Where(tx => DbFunctions.TruncateTime(tx.DateTime) >= from.Date && DbFunctions.TruncateTime(tx.DateTime) <= to.Date
//&& tx.AssetFilled.AssignedToEmployee.Manager
&& tx.AssetFilled.AssignedToEmployee != null
//&
&& tx.AssetFilled.AssetType.Code == "L"
&& (tx.FuelProductType.FuelProductClass.Code == "GAS" || tx.FuelProductType.FuelProductClass.Code == "DSL"))
.GroupBy(tx => new { tx.AssetFilled, tx.DateTime, tx.FuelProductType.FuelProductClass, tx.FuelCard.FuelVendor, tx.City, tx.Volume, tx.Odometer}) //Added tx.volume to have individual transactions
.Select(g => new FuelLightTruckDataSource()
{
Asset = g.FirstOrDefault().AssetFilled,
Employee = g.FirstOrDefault().AssetFilled.AssignedToEmployee,
ProductClass = g.FirstOrDefault().FuelProductType.FuelProductClass,
Vendor = g.FirstOrDefault().FuelCard.FuelVendor,
FillSource = FuelFillSource.Transaction,
Source = "Fuel Station",
City = g.FirstOrDefault().City.ToUpper(),
Volume = g.FirstOrDefault().Volume,
Distance = g.FirstOrDefault().Odometer,
Date = g.FirstOrDefault().DateTime
})
.ToList();
In the end, I use
data.AddRange(dataTransactions);
data.AddRange(dataTransfers);
to put the two lists together and generate a fuel consumption report.
Both lists are individually sorted by Date, but after "AddRange" the "dataTransfers" just gets added to the end, losing my sort by Date. How do I sort the combined result again by date after using the "AddRange" command?
Try this:
data = data.OrderBy(d => d.Date).ToList();
Or if you want to order descending:
data = data.OrderByDescending(d => d.Date).ToList();
You can call List<T>.Sort(delegate).
https://msdn.microsoft.com/en-us/library/w56d4y5z(v=vs.110).aspx
Example:
data.Sort(delegate(FuelLightTruckDataSource x, FuelLightTruckDataSource y)
{
// your sort logic here.
});
Advantage: this sort doesn't create a new IList<T> instance as it does in OrderBy. it's a small thing, but to some people this matters, especially for performance and memory sensitive situations.

Generating Columns in GridView ( C#, LINQ )

The situation is, that i need to create table in grid view looking like this:
----------| ID---|---Name--|--1/2002--|--2/2002--|--1/2003--|........| 2/2009 |
Cust1--|
Cust2--|
:
:
I have two tables in db - Customers and orders, throught LINQ to SQL DataContext
ID and Name of the customers i´m getting from a simple query
var custInfo = from cust in db.Customers
select new { ID = cust.Id,
FullName = cust.FirstName + " " + cust.LastName }
dataGridOrdersPreview.DataSource = custInfo;
And i need some clue, how to generate that columns in format t/year where t indicates the first or second half of the year, and assign to that generated columns each Customer´s orders in that session of the year ( displaying only costs )
[edit]
As far as now, i´m attempting to something like this:
var orders = from ord in db.Orders
group ord by ord.Id_cust into grouped
let costs = grouped
.Where( s => s.YearSession == session && s.Year == year)
.Select(a => new { Costs = a.Cost ) } )
select new { ID = grouped.Key,
Name = custInfo
.Where( a => a.ID == grouped.Key)
.Select( j => j.Name).Single(),
Cost = ExtensionLibrary.Sum(costs, "\n")
};
( in Cost getting only the summed costs in that year session for each customer )
and then i think about iterating throuhgh the years and sessions and getting
somehow the query results to corresponding columns
while (year <= DateTime.Today.Year)
{
year++;
while (session < 2)
{
session++;
dataGridOrdersPreview.Columns.Add(session +"/"+ year);
col.Add((session +"/"+ year),
orders.Select( a => a.Cost ).ToList() );
/* col is Dictionary<string, List<string> > */
}
session = 0;
}
Here i have generated columns that i want and i have orders in Dictionary where Key is column name and Value are orders in that column, but i need some help binding it to that columns
The way I've seen it done is to create a class that has the properties that you want, for example,
class CustOrders
{
public string CustName {get; set;}
public int Orders2002-1 {get; set;}
public int Orders2002-2 {get; set;}
...
public int Orders2009-1 {get; set;}
}
Then use the System.Windows.Forms.BindingSource, call it say CustOrdsBindingSource and set its DataSource to a list of your new class.
List<CustOrders> myListOfCustOrders = new List<CustOrders>();
/* Code to populate myListOfCustOrders */
CustOrdsBindingSource.DataSource = myListOfCustOrders;
In this case you will have to write the code to convert each result of your query results to an instance of CustOrders and store it in myListOfCustOrders.
Finally, the grid view's data source will also have to be set:
gridView1.DataSource = CustOrdsBindingSource;
The big problem I see with this approach is that you will have to change the CustOrders class every year unless there is some voodoo some can suggest to insert properties into the class at run time.
Either way, I hope this gives you a start.
As long as there will be no updating/adding/deleting of rows, I think I would just generate that grid manually.
Fetch the list of customers and the count of how many sales in what year/session. And then in the form take that list and create the needed columns.

Categories

Resources