Is there anyway around this error? I'd like to reuse the same lamba expression in other queries instead of having duplication. Can LinqKit or other linq expression do this?
Error
LINQ to Entities does not recognize the method 'Boolean GetEvent(Tournaments.Data.Entities.Event, System.String)' method, and this method cannot be translated into a store expression.
Code
public MobileEventDetailModel GetDetails(string applicationId)
{
var #event = (from e in _eventsRepository.DataContext.Events.Include(q => q.Assets.Select(a => a.Asset))
where GetEvent(e, applicationId)
select new
{
e.Id,
e.EventParent.Name,
LogoId = (from a in e.Assets
where a.Type == EventAssetType.Logo
select a.AssetId).FirstOrDefault()
}).FirstOrDefault();
return new MobileEventDetailModel
{
Id = #event.Id,
Name = #event.Name,
Logo = string.Format("{0}{1}{2}", Config.BaseUrl, Config.ImagesPath, #event.LogoId)
};
}
public bool GetEvent(Event #event, string applicationId)
{
return #event.Active && #event.Visible && #event.MobileEventApplications.Any(m =>
m.MobileApplication.ApplicationId == applicationId &&
(!m.MobileApplication.ActivationLength.HasValue || EntityFunctions.AddDays(DateTime.Now, 1) < EntityFunctions.AddMonths(m.MobileApplication.DateActivated, m.MobileApplication.ActivationLength.Value)));
}
You need to use an Expression:
public MobileEventDetailModel GetDetails(string applicationId)
{
var event = _eventsRepository.DataContext.Events.Include(q => q.Assets.Select(a => a.Asset))
.Where(GetEvent(applicationId))
.Select(a => new
{
a.Id,
a.EventParent.Name,
LogoId = (from b in a.Assets
where b.Type == EventAssetType.Logo
select b.AssetId).FirstOrDefault()
}).FirstOrDefault();
return new MobileEventDetailModel
{
Id = event.Id,
Name = event.Name,
Logo = string.Format("{0}{1}{2}", Config.BaseUrl, Config.ImagesPath, event.LogoId)
};
}
public Expression<Func<Event, bool>> GetEvent(int applicationId)
{
return = a => a.Active
&& a.Visible
&& a.MobileEventApplications
.Any(m => m.MobileApplication.ApplicationId == applicationId
&& (!m.MobileApplication.ActivationLength.HasValue
|| EntityFunctions.AddDays(DateTime.Now, 1)
< EntityFunctions
.AddMonths(m.MobileApplication.DateActivated, m.MobileApplication.ActivationLength.Value)
)
);
}
Update: Sorry it was late the other night, the changed version is hopefully more what you were looking for.
Related
I'm trying to write following LINQ query using ServiceStack Ormlite.
dbConn.Select<Product>(p => p.IsActive.HasValue && p.IsActive.Value)
Here, Product is my item class and "IsActive" is Nullable Bool property in that class. When this line executes it always throws "InvalidOperationException" with the message
variable 'p' of type '' referenced from scope '', but it is not defined
I tried different variants as following but still same exception result
dbConn.Select<Product>(p => p.IsActive.HasValue == true && p.IsActive.Value == true)
dbConn.Select<Product>(p => p.IsActive != null && p.IsActive.Value == true)
But if I just write
dbConn.Select<Product>(p => p.IsActive.HasValue)
then it works.
I'm puzzled what is the problem? Is this servicestack ormlite issue?
My answer can handle Nullable value like "value" and "HasValue" with servicestack ormlite. And But also with datetime nullable ,like 'createdate.value.Year'.
you must change two place.
modify VisitMemberAccess method:
protected virtual object VisitMemberAccess(MemberExpression m)
{
if (m.Expression != null)
{
if (m.Member.DeclaringType.IsNullableType())
{
if (m.Member.Name == nameof(Nullable<bool>.Value))
return Visit(m.Expression);
if (m.Member.Name == nameof(Nullable<bool>.HasValue))
{
var doesNotEqualNull = Expression.NotEqual(m.Expression, Expression.Constant(null));
return Visit(doesNotEqualNull); // Nullable<T>.HasValue is equivalent to "!= null"
}
throw new ArgumentException(string.Format("Expression '{0}' accesses unsupported property '{1}' of Nullable<T>", m, m.Member));
}
if (m.Member.DeclaringType == typeof(DateTime))
{
var ExpressionInfo = m.Expression as MemberExpression;
if (ExpressionInfo.Member.DeclaringType.IsNullableType())
{
if (ExpressionInfo.Member.Name == nameof(Nullable<bool>.Value))
{
var modelType = (ExpressionInfo.Expression as MemberExpression).Expression.Type;
var tableDef = modelType.GetModelDefinition();
var columnName = (ExpressionInfo.Expression as MemberExpression).Member.Name;
var QuotedColumnName = GetQuotedColumnName(tableDef, columnName);
if (m.Member.Name == "Year")
{
return new PartialSqlString(string.Format("DATEPART(yyyy,{0})", QuotedColumnName));
}
if (m.Member.Name == "Month")
return new PartialSqlString(string.Format("DATEPART(mm,{0})", QuotedColumnName));
}
if (ExpressionInfo.Member.Name == nameof(Nullable<bool>.HasValue))
{
var doesNotEqualNull = Expression.NotEqual(ExpressionInfo.Expression, Expression.Constant(null));
return Visit(doesNotEqualNull); // Nullable<T>.HasValue is equivalent to "!= null"
}
}
else
{
var modelType = ExpressionInfo.Expression.Type;
var tableDef = modelType.GetModelDefinition();
var columnName = ExpressionInfo.Member.Name;
var QuotedColumnName = GetQuotedColumnName(tableDef, columnName);
if (m.Member.Name == "Year")
return new PartialSqlString(string.Format("DATEPART(yyyy,{0})", QuotedColumnName));
if (m.Member.Name == "Month")
return new PartialSqlString(string.Format("DATEPART(mm,{0})", QuotedColumnName));
}
}
if (m.Expression.NodeType == ExpressionType.Parameter || m.Expression.NodeType == ExpressionType.Convert)
{
var propertyInfo = (PropertyInfo)m.Member;
var modelType = m.Expression.Type;
if (m.Expression.NodeType == ExpressionType.Convert)
{
var unaryExpr = m.Expression as UnaryExpression;
if (unaryExpr != null)
{
modelType = unaryExpr.Operand.Type;
}
}
var tableDef = modelType.GetModelDefinition();
if (propertyInfo.PropertyType.IsEnum)
return new EnumMemberAccess(
GetQuotedColumnName(tableDef, m.Member.Name), propertyInfo.PropertyType);
return new PartialSqlString(GetQuotedColumnName(tableDef, m.Member.Name));
}
}
var member = Expression.Convert(m, typeof(object));
var lambda = Expression.Lambda<Func<object>>(member);
var getter = lambda.Compile();
return getter();
}
modify VisitLambda method :
protected virtual object VisitLambda(LambdaExpression lambda)
{
if (lambda.Body.NodeType == ExpressionType.MemberAccess && sep == " ")
{
MemberExpression m = lambda.Body as MemberExpression;
if (m.Expression != null)
{
string r = VisitMemberAccess(m).ToString();
if (m.Member.DeclaringType.IsNullableType())
return r;
return string.Format("{0}={1}", r, GetQuotedTrueValue());
}
}
return Visit(lambda.Body);
}
This is nature of the Linq. In order to achieve what you need, you will need to use two where closes:
dbConn.Where<Product>(p => p.IsActive.HasValue).Where(p=>p.Value==true);
Main Code:
DomainServiceAccountManager d = new DomainServiceAccountManager();
EntityQuery<ListBuy> q = d.GetListMemberBuyQuery();
LoadOperation<ListBuy> l = d.Load(q);
DGListBuy.ItemsSource = l.Entities;
The code:
public IQueryable<ListBuy> GetListMemberBuy()
{
var membuy =
from mem in this.ObjectContext.Members
from b in this.ObjectContext.Buys.Where(b => b.ID_member == mem.ID)
.OrderByDescending(b => b.ID)
.DefaultIfEmpty()
select new { b.ID, mem.Name, b.Money, b.Tarikh };
return membuy;
}
I get the following message:
Cannot implicitly convert type 'System.Linq.IQueryable<AnonymousType#1>' to 'System.Linq.IQueryable<AccountManager.Web.ListBuy>'. An explicit conversion exists (are you missing a cast?)
You method GetListMemberBuy actually returns an IQueryable of anonymous type instead of an IQueryable of type ListBuy. These are not identical, hence the (compile time?) error.
I can only assume that ListBuy also exists in the database, but if so, then you can remove the anonymous type.
public IQueryable<ListBuy> GetListMemberBuy()
{
var membuy =
from mem in this.ObjectContext.Members
from b in this.ObjectContext.Buys.Where(b => b.ID_member == mem.ID)
.OrderByDescending(b => b.ID)
.DefaultIfEmpty()
select new ListBuy() { ID = b.ID, Name = mem.Name, Money = b.Money, Tarikh = b.Tarikh }; // <-- new ListBuy() !!
return membuy;
}
If ListBuy does not exist in the database, then you cannot return an IQueryable. Maybe this will work.
public IEnumerable<ListBuy> GetListMemberBuy()
{
var membuy =
from mem in this.ObjectContext.Members
from b in this.ObjectContext.Buys.Where(b => b.ID_member == mem.ID)
.OrderByDescending(b => b.ID)
.DefaultIfEmpty()
select new { b.ID, mem.Name, b.Money, b.Tarikh };
return membuy
.AsEnumerable()
.Select(b => new ListBuy() {
ID = b.ID, Name = b.Name, Money = b.Money, Tarikh = b.Tarikh
});
}
All this is a bit speculation since you didn't include the ListBuy class definition in your question.
I'm trying to implement a T-SQL equivalent of a where in (select ...) code in LINQ.
This is what I have now:
int contactID = GetContactID();
IEnumerable<string> threadList = (from s in pdc.Messages
where s.ContactID == contactID
group 1 by new { s.ThreadID } into d
select new { ThreadID = d.Key.ThreadID}).ToList<string>();
var result = from s in pdc.Messages
where threadList.Contains(s.ThreadID)
group new { s } by new { s.ThreadID } into d
let maxMsgID = d.Where(x => x.s.ContactID != contactID).Max(x => x.s.MessageID)
select new {
LastMessage = d.Where(x => x.s.MessageID == maxMsgID).SingleOrDefault().s
};
However, my code won't compile due to this error for the ToList():
cannot convert from
'System.Linq.IQueryable<AnonymousType#1>'
to
'System.Collections.Generic.IEnumerable<string>'
Anyone have any suggestions on how to implement this? Or any suggestions on how to simplify this code?
Your query returns a set of anonymous types; you cannot implicitly convert it to a List<string>.
Instead, you should select the string itself. You don't need any anonymous types.
Change it to
var threadList = pdc.Messages.Where(s => s.ContactID == contactID)
.Select(s => s.ThreadID)
.Distinct()
.ToList();
var result = from s in pdc.Messages
where threadList.Contains(s.ThreadID)
group s by s.ThreadID into d
let maxMsgID = d.Where(x => x.ContactID != contactID).Max(x => x.MessageID)
select new {
LastMessage = d.Where(x => x.MessageID == maxMsgID).SingleOrDefault()
};
In her book Entity Framework Julie Lerman recommends using nested queries in preference to joins (scroll back a couple of pages).
In her example see populates 1 field this way, but what id you want to populate 2?
I have an example here where I would prefer to populate the Forename and Surname with the same nested query rather than 2 separate ones. I just need to know the correct syntax to do this.
public static List<RequestInfo> GetRequests(int _employeeId)
{
using (SHPContainerEntities db = new SHPContainerEntities())
{
return db.AnnualLeaveBookeds
.Where(x => x.NextApproverId == _employeeId ||
(x.ApproverId == _employeeId && x.ApprovalDate.HasValue == false))
.Select(y => new RequestInfo
{
AnnualLeaveDate = y.AnnualLeaveDate,
Forename = (
from e in db.Employees
where e.EmployeeId == y.EmployeeId
select e.Forename).FirstOrDefault(),
Surname = (
from e in db.Employees
where e.EmployeeId == y.EmployeeId
select e.Surname).FirstOrDefault(),
RequestDate = y.RequestDate,
CancelRequestDate = y.CancelRequestDate,
ApproveFlag = false,
RejectFlag = false,
Reason = string.Empty
})
.OrderBy(x => x.AnnualLeaveDate)
.ToList();
}
}
There's nothing wrong with your query, but you can write it in a way that is much simpler, without the nested queries:
public static List<RequestInfo> GetRequests(int employeeId)
{
using (SHPContainerEntities db = new SHPContainerEntities())
{
return (
from x in db.AnnualLeaveBookeds
where x.NextApproverId == employeeId ||
(x.ApproverId == employeeId && x.ApprovalDate == null)
orderby x.AnnualLeaveDate
select new RequestInfo
{
AnnualLeaveDate = x.AnnualLeaveDate,
Forename = x.Employee.Forename,
Surname = x.Employee.Surname,
RequestDate = x.RequestDate,
CancelRequestDate = x.CancelRequestDate,
ApproveFlag = false,
RejectFlag = false,
Reason = string.Empty
}).ToList();
}
}
See how I just removed your from e in db.Employees where ... select e.Forename) and simply replaced it with x.Employee.Forename. When your database contains the correct foreign key relationships, the EF designer will successfully generate a model that contain an Employee property on the AnnualLeaveBooked entity. Writing the query like this makes it much more readable.
I hope this helps.
try this
using (SHPContainerEntities db = new SHPContainerEntities())
{
return db.AnnualLeaveBookeds
.Where(x => x.NextApproverId == _employeeId ||
(x.ApproverId == _employeeId && x.ApprovalDate.HasValue == false))
.Select(y =>
{
var emp = db.Emplyees.Where(e => e.EmployeeId == y.EmployeeId);
return new RequestInfo
{
AnnualLeaveDate = y.AnnualLeaveDate,
Forename = emp.Forename,
Surname = emp.Surname,
RequestDate = y.RequestDate,
CancelRequestDate = y.CancelRequestDate,
ApproveFlag = false,
RejectFlag = false,
Reason = string.Empty
};
).OrderBy(x => x.AnnualLeaveDate).ToList();
}
While working on a personal project I wanted a simple service to extract items out of Outlook and host in WCF in a "RESTful" design. In the process I came up with this rather beastly class.
What other scary linq code have people have seen?
public IQueryable<_AppointmentItem> GetAppointments(DateTime date)
{
var dayFlag = (OlDaysOfWeek)(int)Math.Pow(2, (int)date.DayOfWeek);
return
OlDefaultFolders.olFolderCalendar.GetItems<_AppointmentItem>()
.Select(a => new
{
Appointment = a,
RecurrencePattern = a.IsRecurring ?
a.GetRecurrencePattern() : null
})
.Where(a =>
a.Appointment.Start.Date <= date &&
(
(a.RecurrencePattern == null &&
a.Appointment.End.Date >= date) ||
(
a.RecurrencePattern != null &&
(
(a.RecurrencePattern.DayOfMonth == 0 ||
a.RecurrencePattern.DayOfMonth == date.Day) &&
(a.RecurrencePattern.DayOfWeekMask == 0 ||
((a.RecurrencePattern.DayOfWeekMask &
dayFlag) != 0)) &&
(a.RecurrencePattern.MonthOfYear == 0 ||
a.RecurrencePattern.MonthOfYear == date.Month)
)
)
)
)
.Select(a => a.Appointment);
}
[OperationContract()]
[WebGet(
UriTemplate = "/appointments/{year}/{month}/{day}",
RequestFormat = WebMessageFormat.Xml,
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare
)]
[ContentType("text/xml")]
public XElement ListAppointments(string year, string month, string day)
{
try
{
int iYear, iMonth, iDay;
int.TryParse(year, out iYear);
int.TryParse(month, out iMonth);
int.TryParse(day, out iDay);
if (iYear == 0) iYear = DateTime.Now.Year;
if (iMonth == 0) iMonth = DateTime.Now.Month;
if (iDay == 0) iDay = DateTime.Now.Day;
var now = new DateTime(iYear, iMonth, iDay).Date; // DateTime.Now;
return GetAppointments(now).ToXml();
}
catch (System.Exception ex)
{
return new XElement("exception", ex.ToString());
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Microsoft.Office.Interop.Outlook;
namespace WhitedUS.ServiceModel.Office.Linq
{
public static class OutlookUtilities
{
public static IQueryable<T> GetItems<T>(
this OlDefaultFolders defaultFolderType)
{
return
new ApplicationClass()
.Session
.GetDefaultFolder(defaultFolderType)
.Items
.OfType<T>()
.AsQueryable();
}
public static XElement ToXml<T>(this IEnumerable<T> input)
{
if (input == null)
return null;
Type typ = typeof(T);
var root = XName.Get(typ.Name.Trim('_'));
return new XElement(root,
input
.Select(x => x.ToXml<T>())
.Where(x => x != null)
);
}
public static XElement ToXml<T>(this object input)
{
if (input == null)
return null;
Type typ = typeof(T);
var root = XName.Get(typ.Name.Trim('_'));
return new XElement(root,
typ.GetProperties()
.Where(p => p.PropertyType.IsValueType ||
p.PropertyType == typeof(string))
.Select(p => new { Prop = p, Getter = p.GetGetMethod() })
.Where(p => p.Getter != null)
.Select(p => new { Prop = p.Prop, Getter = p.Getter,
Params = p.Getter.GetParameters() })
.Where(p => (p.Params == null || p.Params.Count() <= 0))
.Select(p => new { Name = p.Prop.Name,
Value = p.Getter.Invoke(input, null) })
.Where(p => p.Value != null)
.Select(p => new XAttribute(XName.Get(p.Name), p.Value))
);
}
}
}
Also see: What is the worst abuse you’ve seen of LINQ syntax?
A fully LINQified RayTracer is pretty scary.
Actually, the scariest Linq query I ever saw was my first one. It was just familiar enough to make me think I understood it and just different enough to make me doubt that I really did.