Linq static method error - linq

I have created following function to get dates difference:
public static double MonthsDifference(DateTime dtStart, DateTime dtNow)
{
DateTime start = dtStart;
DateTime end = dtNow;
int compMonth = (end.Month + end.Year * 12) - (start.Month + start.Year * 12);
double daysInEndMonth = (end - end.AddMonths(1)).Days;
double months = compMonth + (start.Day - end.Day) / daysInEndMonth;
return months;
}
I am using it in my LINQ query
var query = from c in context.AccountOwners.Where( MonthsDifference(p.Account.StateChangeDate,DateTime.Now) < 4 )
select c;
return query.Count();
but it is giving error:
LINQ to Entities does not recognize the method 'Double MonthsDifference(System.DateTime, System.DateTime)' method, and this method cannot be translated into a store expression.
Please suggest solution

The MonthsDifference function cannot be mapped to SQL, which is why you are getting this error. You need to either rewrite the query expression without any calls to your own methods to do what you want (which may be impossible -- I don't know exactly which native database functions LINQ to Sql supports), or fetch the result set and do the filtering locally.
The latter approach would go like this:
var count = context.AccountOwners.ToArray()
.Count(o => MonthsDifference(p.Account.StateChangeDate,DateTime.Now) < 4);

If you want to do this in the Linq then you need to inline this method so that Linq2Sql can translate it into sql.
So I think you'll need something like:
var start = DateTime.Now;
var query = from c in context.AccountOwners
let accountDate = c.Account.StateChangeDate
let diff = (start.Month + start.Year * 12) - (accountDate.Month + accountDate.Year * 12) + ...
where diff < 4
select c;
return query.Count();
Linked to Months difference between dates

In LINQ to Entities you can use Entity functions:
using System.Data.Objects;
var query = from c in context.AccountOwners.Where(EntityFunctions.DiffMonths(
p.Account.StateChangeDate,DateTime.Now) < 4 )
select c;
return query.Count();

Related

LINQ to Entities does not recognize the method 'Int32 Parse(System.String)' method

var query = from d in db.mytable
where d.Code == int.Parse(WebUtils.GetQueryString("Code"))
orderby d.PersonInfo
select d;
i get the following error
LINQ to Entities does not recognize the method 'Int32 Parse(System.String)' method, and this method cannot be translated into a store expression.
i have tried to rewrite the int.Parse(WebUtils.GetQueryString("Code")) like this
int intCode = int.TryParse(WebUtils.GetQueryString("OfferCode"));
but still got an error
Just parse your query string outside of the query context:
int code = int.Parse(WebUtils.GetQueryString("Code"));
var query = from d in db.mytable
where d.Code == code
orderby d.PersonInfo
select d;
You can convert the 'Code' field to string instead of the query string to int.
This should works:
var queryString = WebUtils.GetQueryString("Code");
var query = from d in db.mytable
where SqlFunctions.StringConvert(d.Code) == queryString
orderby d.PersonInfo
select d;
There is no way to convert the string to int. EF doesn't know how to translate that to SQL if you use int.Parse

How to query and calculate dates in the where clause of a LINQ statement?

I am having trouble with the following piece of code. Before I paste it, Let me give a bit of history on what should happen.
I have a model containing 2 fields of interest at the moment, which is the name of the order the customer placed, and the date at which he/she placed it. A pre-calculated date will be used to query the dateplaced field (and should only query the dates , and not the time). The query counts the amount of duplicates that occur in the MondayOrder field, and groups them together. Now , when I exclude the where clause which should query the dates, the query runs great. However, The goal of this query is to count the amount of orders for the following week based on the date the order has been placed.
List<string> returnlist = new List<string>();
DateTime dt = getNextWeekMondaysDate().Date;
switch (day)
{
case DayOfWeek.Monday:
{
var CountOrders =
from x in Data.EntityDB.Orders
group x by x.MondayOrder into m
let count = m.Count()
select new
{
MondayOrderItem = m.Key, Amount = count
};
foreach (var item in CountOrders)
{
returnlist.Add(item.MondayOrderItem + " : " +
item.Amount);
}
}
break;
The getNextWeekMondaysDate() method has an overload which I can use, where if I supply it a date, it will get the following Monday's date from the parameter given. The problem is though, LINQ does not accept queries such as the following:
var CountOrders =
from x in Data.EntityDB.Orders
where getNextWeekMondaysDate(x.DatePlaced.Value).Date == dt
group x by x.MondayOrder into m
let count = m.Count()
select new { MondayOrderItem = m.Key, Amount = count };
This is exactly what I must achieve. Is there any workaround for this situation?
UPDATE
Here is the exception I get when I try the 2nd query.
LINQ to Entities does not recognize the method 'System.DateTime getNextWeekMondaysDate(System.DateTime)' method, and this method cannot be translated into a store expression.
You cannot do this directly, as user-defined method calls cannot be translated to SQL by the EF query provider. The provider recognizes a limited set of .NET methods that can be translated to SQL and also a number of canonical functions as well. Anything that cannot be expressed using these methods only is off-limits unless you write your own query provider (which is only theoretically an option).
As a practical workaround, you can calculate an appropriate range for x.DatePlaced.Value in code before the query and then use specific DateTime values on the where clause.
As an intellectual exercise, note that this method is recognized by the query provider and can be used as part of the expression. So this abomination should work too:
var CountOrders =
from x in Data.EntityDB.Orders
where EntityFunctions.AddDays(
x.DatePlaced.Date.Value,
(9 - DateAndTime.DatePart(DateInterval.WeekDay, x.DatePlaced.Value)) % 7)
.Date == dt
group x by x.MondayOrder into m
let count = m.Count()
select new { MondayOrderItem = m.Key, Amount = count };
Linq to Entities doesn't know how to convert arbitrary C# methods into SQL - it's not possible in general.
So, you have to work with the methods it does understand.
In this case, you could do something like this:
DateTime weekBegin = CalculateWeekBegin( dt );
DateTime weekEnd = CalculateWeekEnd( dt );
var CountOrders =
from x in Data.EntityDB.Orders
where x.DatePlaced.Value >= weekBegin && x.DatePlaced.Value < weekEnd
group x by x.MondayOrder into m
let count = m.Count()
select new { MondayOrderItem = m.Key, Amount = count });

Linq to NHibernate, Order by Rand()?

I'm using Linq To Nhibernate, and with a HQL statement I can do something like this:
string hql = "from Entity e order by rand()";
Andi t will be ordered so random, and I'd link to know How can I do the same statement with Linq to Nhibernate ?
I try this:
var result = from e in Session.Linq<Entity>
orderby new Random().Next(0,100)
select e;
but it throws a exception and doesn't work...
is there any other way or solution?
Thanks
Cheers
I guess Linq to NHibernate is unable to convert the Random.Next call to SQL...
An option would be to sort the results after you retrieve them from the DB :
var rand = new Random();
var query = from e in Session.Linq<Entity>
select e;
var result = from e in query.AsEnumerable()
orderby rand.Next(0,100)
select e;
Note that you need to use a single instance of Random, because the seed is based on the current number of ticks ; if you create several instances of Random with very short interval, they will have the same seed, and generate the same sequence.
Anyway, sorting a collection based on a random number is not such a good idea, because the sort won't be stable and could theoretically last forever. If you need to shuffle the results, you can use the Fisher-Yates algorithm :
var result = Session.Linq<Entity>().ToArray();
var rand = new Random();
for(int i = result.Length - 1; i > 0; i--)
{
int swapIndex = rand.Next(i + 1);
var tmp = result[i];
result[i] = result[swapIndex];
result[swapIndex] = tmp;
}

LINQ: concatenate multiple int properties into a string

I have an object with two different integer properties in it, and I'm trying to get a a new object in Linq to Entities, combining two integer properties from the same object as concatenated strings, as follows
List<DateRange> collection = (from d in context.dates
select new DateRange
{
DateString = from s in context.Seasons
where s.SeasonID = d.DateID
select string.Format("{0} - {1}", s.StartYear, s.EndYear) }
).ToList<DateRange>();
The string concatenation of the years will not compile.
This will work in LINQ to Objects, provided that each object in objects is a class or struct containing "Number1" and "Number2" fields or properties:
var results = from o in objects
select string.Format("{0} - {1}", o.Number1, o.Number2);
(However, your original should work, as well....)
Assuming you are connecting to a database via LINQ to SQL/Entities, then the String.Format call will likely fail, as with those providers, the select clause is executed within the database. Not everything can be translated from C# into SQL.
To convert your database results into a string like you want to, the following should work:
var temp = (
from d in context.dates
from s in context.Seasons
where s.SeasonID == d.DateID
select new { s.StartYear, s.EndYear }
).ToList(); // Execute query against database now, before converting date parts to a string
var temp2 =
from t in temp
select new DateRange
{
DateString = t.StartYear + " - " + t.EndYear
};
List<DateRange> collection = temp2.ToList();
EDIT:
I had an additional thought. The String.Format call is most likely the problem. I am not sure if it would work or not, but what about a plain-jane concat:
List<DateRange> collection =
(from d in context.dates
select new DateRange
{
DateString = from s in context.Seasons
where s.SeasonID = d.DateID
select s.StartYear + " - " + s.EndYear
}
).ToList<DateRange>();
Your original code works if you really want what you wrote. However, if your really want to get from
var objects = new MyObject[]{
new MyObject {Int1 = 1, Int2 = 2},
new MyObject {Int1 = 3, Int2 = 4}};
something like 1 - 2 - 3 - 4 you can write
var strings = objects.Select(o = > string.Format("{0} - {1}", o.Int1, o.Int2).ToArray();
var output = string.Join(" - ", strings);
using System.Data.Objects.SqlClient;
:
:
List<DateRange> collection = (from d in context.dates
select new DateRange
{
DateString = from s in context.Seasons
where s.SeasonID = d.DateID
select SqlFunctions.StringConvert((double)s.StartYear) + " - " +
SqlFunctions.StringConvert((double)s.EndYear)
}).ToList<DateRange>();
The StringConvert method gets converted into the proper conversion function when the LINQ statement is converted to SQL for execution on the server.

date difference with linq

With this code:
i.SpesaAlloggio = db.TDP_NotaSpeseSezB.Sum(p => p.Costo / (((DateTime)p.DayEnd)
.Subtract((DateTime)p.DayStart).Days + 1));
I receive this error:
LINQ to Entities does not recognize the method
'System.TimeSpan Subtract(System.DateTime)' method, and this method cannot be
translated into a store expression.
How can I do this?
Use a calculated DB field and map that. Or use SqlFunctions with EF 4 as LukLed suggested (+1).
I wrote a function for removing time:
public static DateTime RemoveHours(DateTime date)
{
int year = date.Year;
int month = date.Month;
int day = date.Day;
return new DateTime(year, month, day);
}
and changed filtering condition:
var query =
from trn in context.IdentityTransactions
where trn.ClientUserId == userId && trn.DateDeleted == null
orderby trn.DateTimeCreated
select new
{
ClientServerTransactionID = trn.ClientServerTransactionID,
DateTimeCreated = trn.DateTimeCreated,
ServerTransDateTime = trn.ServerTransDateTime,
Timestamp = trn.Timestamp,
Remarc = trn.Remarc,
ReservedSum = trn.ReservedSum,
};
if (dateMin.HasValue && dateMin.Value > DateTime.MinValue)
{
DateTime startDate = Converters.RemoveHours(dateMin.Value);
query = from trn in query
where trn.DateTimeCreated >= startDate
select trn;
}
if (dateMax.HasValue && dateMax.Value > DateTime.MinValue)
{
var endDate = Converters.RemoveHours(dateMax.Value.AddDays(1.0));
query = from trn in query
where trn.DateTimeCreated < endDate
select trn;
}
dateMin and dateMax are nullable types and may be not set in my case.
Try (it is not very efficient, but it will work):
i.SpesaAlloggio = db.TDP_NotaSpeseSezB.ToList()
.Sum(p => p.Costo / (((DateTime)p.DayEnd)
.Subtract((DateTime)p.DayStart).Days + 1));
EDIT : This will be extremely slow for large tables, because it transfers whole table content form server
Entity Framework tries to translate your expression to SQL, but it can't handle ((DateTime)p.DayEnd).Subtract((DateTime)p.DayStart). You have to make it simpler. ToList() gets all rows and then makes the calculation on application side, not in database.
With EF4, you could use SqlFunctions DateDiff
With EF1, you could create calculated field or view with this field and make calculation based on this field.

Resources