How to return custom objects using Except - c#

I'm using ASP.NET MVC, C# and SQL Server.
I want to get a list of cars that are available for rent within a certain date, ie. not already rented out.
What I got now is something like taking all the cars from the cars table, except the ones that have an order at the specified date (instead of checking each car individually for an order):
var query = db.Cars.Select(r => r.ID)
.Except(db.Orders
.Where(o => (startDate >= o.RentalStart
&& startDate <= o.RentalReturn))
Select(r => r.Car.ID));
The problem is that I want to return a custom object, and I'm not sure how do that using except, so I could always get the ID, and based on the ID get the entire object with a different method/query.
But I'd like to get something like:
Select(c => new myModel
{
ID = c.ID,
property1 = c.property1,
property2 = c.property2,
property3 = c.property3,
property4 = c.property4,
});

What you can do is filter the Cars list where the ID is not contained in the set of invalid order IDs.
var invalidOrders = db.Orders
.Where(o => startDate >= o.RentalStart && startDate <= o.RentalReturn)
.Select(r => r.Car.ID)
var query = db.Cars.Where(car => !invalidOrders.Contains(car.ID));

Related

EF core get data from entity per day by limit

This is an entity
public class ViewModel
{
public string Id { get; set; }
public DateTime Start { get; set; }
public string Name { get; set; }
}
This is my context query,works with ef core in dbcontext.
var list = _Service.GetDataByMonth(start,end).ToList();
// it returns all entity between giving start, end param.
// start and end is Datetime property comes from ajax. This code works fine it return almost 1k objectlist with type of ViewModel
like
[0] Id="1",Title="sample",Start:""15.12.2020"
[1] Id="2",Title="sample2",Start:""15.12.2020"
[2] Id="3",Title="sample3",Start:""16.12.2020"
[3] Id="4",Title="sample4",Start:""16.12.2020"
As shows above we got almost 20+ entity per day.
I can get count per day like
var listt = _Service.GetDataByMonth(start,end).GroupBy(x => x.Start.Date).Select(grp => new { Date = grp.Key, Count = grp.Count() });
[0] Key:""15.12.2020",Count:20
[1] Key:""16.12.2020",Count:25
[2] Key:""17.12.2020",Count:44
it returns like this.
So what i want is giving start and end param a funciton then get 3 values per day between giving datetime object
NEW
var list1= _Service.GetDataByMonth(start,end).GroupBy(x => x.StartDate.Date)
.Select(grp => grp.Take(3)).ToList();
//this type List<Ienumerable<Viewmodel>>
var list2 = _Service.GetDataByMonth(start,end).GroupBy(x => x.StartDate.Date).Select(grp => grp.Take(3).ToList()).ToList();
// this type List<List<Viewmodel>>
My want it List<Viewmodel>
service
...
return entity.Where(x =>
x.IsDeleted == false &&
(x.StartDate.Date >= start.Date && x.StartDate.Date <=end.Date)
).OrderBy(x => x.FinishDate).ToList();
// it work with this way but bad way
var lis = list.SelectMany(d => d).ToList();
Yes I figuredout using selectmany instead of select works fine. Thank you again
You can use .Take() to only take 3 items of each group:
_Service.GetDataByMonth(start,end)
.GroupBy(x => x.Start.Date)
.Select(grp => new { Data = grp.Take(3).ToList(), Date = grp.Key, Count = grp.Count() })
.ToList();
var list1= _Service.GetDataByMonth(start,end).GroupBy(x => x.StartDate.Date)
.Select(grp => grp.Take(3)).ToList();
It returns List<List> maybe it will help some one bu my need is comes from with this code
This code makes list of list each element is list and contians 3 object.
var list1= _Service.GetDataByMonth(start,end).GroupBy(x => x.StartDate.Date)
.SelectMany(grp => grp.Take(3)).ToList();
Many makes just list. It mades list with ordered objects

Group by some columns depending on values in Entity Framework

I have the following simple statement in my Entity Framework code:
query = query
.Where(c => c.NotificationType == NotificationType.AppMessage)
.GroupBy(c => c.ConversationId)
.Select(d => d.OrderByDescending(p => p.DateCreated).FirstOrDefault());
It simply finds the latest Notification based on a group by with conversationId and select latest. Easy.
However, this is ONLY what I want if c.NotificationType == NotificationType.AppMessage. If the column is different than AppMessage (c.NotificationType <> NotificationType.AppMessage), I just want the column. What I truly Want to write is a magical statement such as:
query = query
.Where(c => (c.NotificationType <> NotificationType.AppMessage)
|| ((c.NotificationType == NotificationType.AppMessage)
.GroupBy(c => c.ConversationId)
.Select(d => d.OrderByDescending(p => p.DateCreated).FirstOrDefault()));
But this doesn't make sense because the GroupBy/Select is based on the first where statement.
How do I solve this?
The simplest way is to compose UNION ALL query using Concat at the end of your original query:
query = query
.Where(c => c.NotificationType == NotificationType.AppMessage)
.GroupBy(c => c.ConversationId)
.Select(d => d.OrderByDescending(p => p.DateCreated).FirstOrDefault())
.Concat(query.Where(c => c.NotificationType != NotificationType.AppMessage));
public class EntityClass
{
public int NotificationType { get; set; }
public int ConversationId { get; set; }
public DateTime Created { get; set; }
public static EntityClass GetLastNotification(int convId)
{
var list = new List<EntityClass>(); // Fill the values
list = list
.GroupBy(i => i.ConversationId) // Group by ConversationId.
.ToDictionary(i => i.Key, n => n.ToList()) // Create dictionary.
.Where(i => i.Key == convId) // Filter by ConversationId.
.SelectMany(i => i.Value) // Project multiple lists to ONLY one list.
.ToList(); // Create list.
// Now, you can filter it:
// 0 - NotificationType.AppMessage
// I didn't get what exactly you want to filter there, but this should give you an idea.
var lastNotification = list.OrderByDescending(i => i.Created).FirstOrDefault(i => i.NotificationType == 0);
return lastNotification;
}
}
you filter your list with "GroupBy" based on ConversationId. Next, create a dictionary from the result and make only one list (SelectMany). Then, you already have one list where should be only records with ConversationId you want.
Last part is for filtering this list - you wanted to last notification with certain NotificationType. Should be working :)

selecting a single item from grouped linq query based on a condition

I am struggling with a grouping linq query
I have this:
DateTime dateFrom = new Date(2014,8,2);
var GroupedPrices = Prices.Where(p => p.ArrivalDateFrom <= dateFrom
&&
p.ArrivalDateTo > dateFrom)
.GroupBy(p => p.ItemID);
I am trying to get to a single price of each ID - eg. in/from each group, based on the newest ValidFrom date of that price.
I have started by grouping them by their ItemID's (not the individual price record id's) but am struggling in working out how to grab just a single one based on that newest ValidFrom date. I thought I could order them before grouping, but wasn't sure that would stick after the grouping was done.. ie
expecting it will use a Max(x=>x.ValidFrom) type thing or OrderByDescending(x=>x.ValidFrom).First() but cant work that out
any help much appreciated
thanks
I think you just need to select what you want, at the end, like so:
DateTime dateFrom = new Date(2014,8,2);
var GroupedPrices = Prices
.Where(p => p.ArrivalDateFrom <= dateFrom && p.ArrivalDateTo > dateFrom)
.GroupBy(p => p.ItemID)
.Select(g => new{ ItemId = g.Key, NewestPrice = g.OrderByDescending(p => p.ValidFrom).First() });

LINQ projection combining date and list

I have a list of objects containg value and date of transaction.
DateTime Date { get ; set; }
double Value { get; set; }
I want to get the new grouped object which will contain date of transaction and list of values for this particular day.
I can retrieve both list and date but i dont know how to use projection to cast them into new object.
var res1 = ExpenseList.Where(p => p.Date == Convert.ToDateTime("01-12-2013"))
.Select(p => p.Value)
.ToList();
DateTime res2 = ExpenseList.Where(p => p.Date == Convert.ToDateTime("01-12-2013"))
.Select(p => p.Date)
.FirstOrDefault();
There might have been some confusion around I will post pictures to clarify
I have something like this in ExpenseList set of date and value
I want one Date and Collection of Values
To group all of the values for a particular day you'll want to use GroupBy
var groups = ExpenseList.GroupBy(expense => expense.Date,
expense => expense.Value);
ExpenseList.Where(p => p.Date == Convert.ToDateTime("01-12-2013"))
.Select(p => new MyObject {Date = p.Date, Value = p.Value})
.ToList();
Replace MyObject for the actual type you have defined.

LINQ Method that returns set based on filtered sub-set

I have 2 tables. 1 has entity's, 1 per row. Another is simply a mapping table of my EntitiesID and EmployeeID. I am trying to write a LINQ method that returns all Entities from the First Table where the EntityID is in the mapping table that is filtered by the EmployeeID.
Simplified Table Structure Example
TaskTable: ID, Description, Status
TaskViewTable: ID, TaskID, EmployeeID
So I want to return all Rows from TaskTable where the ID is in a SubQuery results of TaskViewTable based on EmployeeID.
Any help on doing this in LINQ? I have a 1 to Many set up between the two tables as well. I know there are similar questions am maybe I'm dense but they didn't seem to apply completely to what I was asking.(e.g. Linq Return Filtered Children)
Sorry forgot to show what I have so far:
IQueryable<tblTask> tTask=context.GetTable<tblTask>();
return tTask.Where(t => t.tblTasksViews.Where(v => v.EmployeeID == empID))
It, however, does not like my wherewith an unkown method Where(?)
Something like this should do the trick:
var tasks = tTask.Where(t =>
tTaskView.Where(v => v.ID == empId).Select(v => v.TaskId).Contains(t.ID));
You could break up the above into two sections:
//1.) Get all task views for the employeeID and only select the mapped TaskId
var taskViews = tTaskView.Where(v => v.ID == empId).Select(v => v.TaskId); //taskViews = IEnumerable<int>
//2.) Then get all tasks from the filtered task ids
var tasks = tTask.Where(t => taskViews.Contains(t.ID));
UPDATE
//3.) Project filtered results into IEnumerable<Task>
return tasks.Select(t => new Task()
{
ID = t.ID,
ActionableID = t.ActionableID,
StatusID = t.StatusID,
TypeID = t.TypeID,
Description = t.Description
});
You can, of course, string everything into a nice one-liner:
public List<Task> GetTasks(int empId)
{
return tTask
.Where(t => tTaskView.Where(v => v.ID == empId).Select(v => v.TaskId).Contains(t.ID))
.Select(t => new Task()
{
ID = t.ID,
ActionableID = t.ActionableID,
StatusID = t.StatusID,
TypeID = t.TypeID,
Description = t.Description
}).ToList();
}
Try something like this:
var query =
from tt in TaskTable
join tvt in TaskViewTable on tt.ID equals tvt.TaskID into xs
where xs.Any(z => z.EmployeeID == empID)
select tt;

Categories

Resources