how can i convert datetime exactly to sql server datetime using linq - linq

I have two fields in Model class
public DateTime START_DATE { get; set; }
public DateTime END_DATE { get; set; }
and a Class
string format = "yyyy-MM-dd hh:mm:ss";
string startdate = timesheetModel.START_DATE.ToString(format, DateTimeFormatInfo.InvariantInfo);
string enddate = timesheetModel.END_DATE.ToString(format, DateTimeFormatInfo.InvariantInfo);
var weekid = from data in db.WEEK_CALENDER
where data.WEEK_START_DT ==Convert.ToDateTime(startdate) && data.WEEK_END_DT == Convert.ToDateTime(enddate)
select data.ID;
But Getting Error Convert.ToDateTimes is not possible in linq
and Also in Sql Server as format like
2014-03-03 00:00:00.000
I Have tried in different ways, but i think it needs exact same format of sql server format.
and Tried in that format also , but not getting.
pls help me anyone.

You don't need to convert your datetime to string, this can only cause trouble
public DateTime START_DATE { get; set; }
public DateTime END_DATE { get; set; }
var weekid = from data in db.WEEK_CALENDER
where data.WEEK_START_DT == START_DATE && data.WEEK_END_DT == END_DATE
select data.ID;
Unless you are managing different type of calendar, weeks don't overlap and they all contain 7 days, so you should only need to check the WEEK_START_DT (or only WEEK_END_DT) and you will only get 1 week, so you could do this instead :
var weekid = db.WEEK_CALENDER.Single(data => data.WEEK_START_DT == START_DATE).ID;
An other idea, your method receives a single date, and if returns the weekId which contains this date, it doesn't have to be the specific start of the week, it could be any date. This won't work of course if you are managing different type of weeks in your table.
var weekid = db.WEEK_CALENDER.Single(data =>
data.WEEK_START_DT <= A_DATE
&& data.WEEK_END_DT >= A_DATE
).ID;

Related

Correct interpretation of SQL request by EF Core

I have a certain table in the database that stores the following objects:
public partial class Invoice
{
public string DocumentNumber { get; set; }
public DateTime? DocumentDate { get; set; }
public string DocumentReference { get; set; }
public string SerialNumber { get; set; }
public string ProductCode { get; set; }
public string Description { get; set; }
public string Certificate { get; set; }
public string Language { get; set; }
public string Email { get; set; }
}
I also have a query that returns me the number of specific elements:
SELECT Count(*)
FROM (
SELECT DocumentNumber,DocumentDate,DocumentReference
FROM vInvoiceSwivelInfoWeb
WHERE Email = 'someemail#gmail.com' AND Language = 'FR'
GROUP BY DocumentNumber,DocumentDate,DocumentReference
) AS T
The answer looks something like this:
How to use EF to make such a request and get a numerical answer?
I tried like this:
_context.Database.ExecuteSqlRawAsync($"..some SQL query..")
but I do not get the expected result.
UPD: Having received the answer about the impossibility of fulfilling this request through EF, the following question reasonably arose: Is it possible to make this request using LINQ?
You can Leverage ADO.NET via the Context.Database property.
Unfortunately, there is no way to get the count from the database using EF Core execute methods if you have a custom query that is not related to your entities.
using (var command = context.Database.GetDbConnection().CreateCommand())
{
command.CommandText = "SELECT Count(*) From Table1";
context.Database.OpenConnection();
using (var result = command.ExecuteReader())
{
// do something with result
}
}
for Updated question
var count = from a in _context.vInvoiceSwivelInfoWeb
where a.Email == "someemail#gmail.com" && a.Language == "FR"
group new { a.DocumentNumber , a.DocumentReference , a.DocumentDate } by a into g
select g.Count()
also, it's important to know which version of EF-Core are you using:
currently, if you are using EF-Core 3 group-by doesn't translate to SQL command so you have to do it on client-side:
check this link :
https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-3.0/breaking-changes#linq-queries-are-no-longer-evaluated-on-the-client
for EF-Core 3.0 - 3.1.1
var count = _context.vInvoiceSwivelInfoWeb
.Where(a => a.Email == "someemail#gmail.com" && a.Language == "FR" ).ToList()
.GroupBy(a => new { a.DocumentNumber ,a.DocumentDate, a.DocumentReference }).Count();

How to dynamically add properties to a LINQ GroupBy clause

I have a class Product:
class Product
{
int Id { get; set; }
string Name { get; set; }
int CategoryId { get; set; }
int PlantId { get; set; }
DateTime ProductionDate { get; set; }
}
I would like to use the LINQ GroupBy on multiple properties but I do not know in advance how many and which properties. For instance I might want to group by just CategoryId, just PlantId or both. I found an article on the net that describes how to use LINQ GrouBy dinamically.
This might work good indeed but if I want to perform the Group By on ProductionDate.Year and ProductionDate.Month without knowing the granularity in advance? As granularity I mean whether I want to group all the Products produced in a specific year or narrow the group by to the month.
The only logical solution that I found is:
public ProductInfo GetGroupedProducts(int? year, int? month, int? selectedCategoryId, int? selectedPlantId)
{
List<Product> products = GetProducts();
var groupedProducts = products.GroupBy(p => new { (year == null ? p.ProductionDate.Year : string.Empty),
(month == null ? p.ProductionDate.Month : string.Empty),
(selectedCategoryId == null ? p.CategoryId : string.Empty),
(selectedPlantId == null ? p.PlantId : string.Empty)
});
//perform some additional filtering and assignments
}
But I guess there could be a cleaner and more proper solution. With the old style way of building queries, based on strings, this task was much easier to accomplish. If there is no other way, I really think this is a part of LINQ that needs to be improved.
The cleaner solution is to use this extension method:
public static TResult With<TInput, TResult>(this TInput? o, Func<TInput, TResult>
selector, TResult defaultResult = default(TResult)) where TInput : struct
{
return o.HasValue ? selector(o.Value) : defaultResult;
}
Like this:
string result = year.With(T => p.ProductionDate.Year, string.Empty);
of this, if nulls are okay:
string result = year.With(T => p.ProductionDate.Year);
or something with T which is int in case the int? has value.
But, you know, the better solution is out there, so feel free to expand your code so I could analyze it.
If I understand what you are asking, I had a similar issue Reversing typeof to use Linq Field<T>
I would do something like
public static IEnumerable<IGrouping<string, TElement>> GroupMany<TElement>(
this IEnumerable<TElement> elements,
params Func<TElement, object>[] groupSelectors)
{
return elements.GroupBy(e => string.Join(":", groupSelectors.Select(s => s(e))));
}
then you can call your function like
var groupedProducts = products.GroupMany(p => p.CategoryId , p => p.ProductionDate.Month);
The function groups via a string of the properties divided by a colon. The reason why I did this is because the hashcode for strings are guaranteed to be the same as opposed to a class.

format datetime value in C#

i want to format date time value in this format ("yyyy/MM/dd")
below is the code, m using to do so
DateTime? date = DateTime.Now;
DateTime? formattedDate = Convert.ToDateTime(date.Value.ToString("yyyy/MM/dd"));
Console.WriteLine(formattedDate);
Console.ReadLine();
the code work fine but you can see in the above code that i have declared datetime variable as null which in reverse causing the problem
please suggest what i am doing wrong in the above code.
as i am getting the output as this 9/10/2012 12:00:00 AM
Thanks,
Aaman
The problem is that what you call formattedDate is actually yet another instance of a DateTime. There's no notion of format inside the native .NET DateTime structure. You can talk about formatting only when you convert it to a string:
DateTime date = DateTime.Now;
string formattedDate = date.ToString("yyyy/MM/dd"));
Console.WriteLine(formattedDate);
or if you want to use a nullable DateTime:
DateTime? date = DateTime.Now;
string formattedDate = date.Value.ToString("yyyy/MM/dd"));
Console.WriteLine(formattedDate);
But since your question is tagged with asp.net-mvc-3, there are other ways to format values. For example using the [DisplayFormat] attribute on your view model:
[DisplayFormat(DataFormatString = "{0:yyyy/MM/dd}", ApplyFormatInEditMode = true)]
public DateTime? Date { get; set; }
and in your view if you want to display the value of your view model:
#Html.DisplayFor(x => x.Date)
or if you want to generate an input field with properly formatted value:
#Html.EditorFor(x => x.Date)

sorting data based on month and date

My db structure is following:
long OccasionId { get; set; }
string OccasionName { get; set; }
string OccasionDesc { get; set; }
DateTime OccasionDate { get; set; }
I need my result on html in following format
February
OccasionName1
5th February
OccasionDesc1
OccasionName2
7th February
OccasionDesc2
Now the data has to be sorted and grouped by month and then date but not year; means if there are two dates 05/02/1974 and 07/02/1970, even though the second date comes first because of the year, I need the sorting to be such that 5th feb comes first.
I'm using entity framework and asp.net mvc
Thanks
Arnab
Well, you don't mention your DB, but on SQL Server:
var q = from o in Context.Occasions
orderby o.Month, o.Day
select o;
...should work. Did you try that? However, it may or may not be efficient depending on the particulars of the rest of the query.

Linq expression for filtered collection of collections?

I'm hoping this will be a rather simple question for anyone who's good at Linq. I'm struggling to come up with the right Linq expression for the following. I'm able to hack something to get the results, but I'm sure there's a proper and simple Linq way to do it, I'm just not good enough at Linq yet...
I have a database accessed through Entity Framework. It has a number of Tasks. Each Task has a collection of TimeSegments. The TimeSegments have Date and Employee properties.
What I want is to be able to get the tasks for a certain employee and a certain month and the timesegments for each task for that same month and employee.
Again, the tasks do not in themselves have month nor date information, but they do by the TimeSegments associated with each task.
Very simplified it looks sort of like this:
public class Model //Simplified representation of the Entity Framework model
{
public List<Task> Tasks { get; set; }
}
public class Task
{
public int Id { get; set; }
public List<TimeSegment> TimeSegments { get; set; }
public Customer Customer { get; set; }
}
public class TimeSegment
{
public int Id { get; set; }
public string Date { get; set; }
public Employee Employee { get; set; }
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
}
So how do I do this as simply as possible with Linq? I.e. tasks and associated timesegments for a certain month and employee. I would also like to be able to get it by Customer BTW...
This is the simplest thing I could come up with:
var tasksWithSegments =
from segment in model.TimeSegments
where segment.Date.Month == month
where segment.Employee.Id == employeeId
group segment by segment.Task into result
select new
{
Task = result.Key,
TimeSegments = result.ToArray()
};
Please note that you might have to add some properties to your model, such as Model.TimeSegment and TimeSegment.Task.
The trick with LINQ queries often is to start at the right collection. In this case the ideal starting point is TimeSegments.
ps. I'm not sure whether Date.Month == month will actually work with EF, but I think it will (with EF 4.0 that is).
Update:
Could you show how to extend this
query and get the tasks for a
particular Customer as well?
I'm not sure what you mean, but you can for instance filter the previous queryable like this:
var tasksWithSegmentsForCustomers =
from taskWithSegments in tasksWithSegments
where taskWithSegments.Task.Customer.Id == customerId
select taskWithSegments;
Can I get the return type to be a list
of Tasks with a list of TimeSegments
if I have this in a method?
Again, not sure what you exactly want, but if you want two separate lists that have no relation, you can do this:
List<Task> tasks = (
from taskWithSegments in tasksWithSegments
select taskWithSegments.Task).ToList();
List<TimeSegments> segments = (
from taskWithSegments in tasksWithSegments
from segment in taskWithSegments.Segments
select segment).ToList();
Of course, if this is what you need, than it might be easier to rewrite the original query to something like this:
List<TimeSegment> segments = (
from segment in model.TimeSegments
where segment.Date.Month == month
where segment.Employee.Id == employeeId
select segment).ToList();
List<Task> allTasks =
segments.Select(s => s.Task).Distinct().ToList();
Once you got the hang of writing LINQ queries, there is no way you want to go back to writing SQL statements or old-fashion foreach statements.
Think LINQ!!!
What I want is to be able to get the
tasks for a certain employee and a
certain month and the timesegments for
each task for that same month and
employee.
This will select tasks from an instance of Model where the task has at least one time segment that in the requested month for the requested employee (untested):
Model model = new Model();
tasks = model.Tasks.Where(t => t.TimeSegments.Any(ts => ts.Employee.Id = requestedId && Convert.ToDate(ts.Date).Month == requestedMonth));

Resources