Suppose I have a function call from EF like:
var result = context.myFunction();
the result type is ObjectResult<int?>. Then I want to use linq to get the single value.
How to write the linq?
Maybe something like this
result.SkipWhile(o => !o.HasValue).Take(1)
Related
I'm trying to perform a LIKE clause in an entity query. The examples I've seen use dynamic linq to do this kind of thing, but my code...
var query = context.StudySet
.Where("it.PatientName LIKE #patientName", new ObjectParameter("patientName", patientName);
...gives me a System.Linq.Dynamic.ParseException with
Additional information: Expression of type 'Boolean' expected
context is a DbContext from EF 6 code-first, patientName is a string
Please tell me what's wrong with my code?
if you want use DynamicLINQ you need change your code like this
var query = context.StudySet.Where("it.PatientName.Contains(#0)", patientName);
because DynamicLinq can't parse LIKE operator
I've realised my mistake.
I had assumed the method to pass the query was part of Dynamic Linq but actually it's just a variant of the standard Where method on ObjectQuery. If I get the ObjectContext from my (code first) DbContext it's all good.
ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;
ObjectSet<Study> studySet = objectContext.CreateObjectSet<Study>();
var query = studySet.
Where("it.PatientName LIKE #patientName", new ObjectParameter("patientName", patientName));
I don't know of a way to use like with a LINQ query, but you could use a raw SQL query:
var query = context.StudySet.SqlQuery(
"select * from StudySet where PatientName LIKE #patientName",
new SqlParameter("#patientName", patientName));
How can i convert linq to object query or any other Func delegate to string like sql statements
for example
var cat_list = new List<Cat> { ... };
var myquery = cat_list.Where(x => x.Age > 2 && x.Name.Contains("Kitty"));
Now myquery is IEnumerable<Cat>. how can i convert this to simply something like this
"Age > #p1 AND Name LIKE #p2"
how can i achieve this ??
Doing something like that is not simple. Have a look at the series of articles Building an IQueryable provider by Matt Warren. All the code he uses is available as a library too. That should help you get started.
You could write an expression tree parser and generate the sql. Your description contains a fault - myquery isn't IQueryable<Cat>, it is an IEnumerable<Cat>. As you tagged it correctly, this is linq-to-objects, not linq-to-sql. There is no information in the calls to construct a query.
Check out the method DataContext.GetCommand() which is passed an IQueryable object and returns the DbCommand object that corresponds to the query. The CommandText property of the DbCommand object shows the text of the query.
I think we are basically looking for a extension method that could take in an IQueryable and return an IQueryable based on an entire query statement and not just the where statement.
Example of what we would like for a Search Method:
IRepository<Person> repository = new Repository<Person>();
var results = repository.GetQuery().Include("Names").Search([dynamic linq here]);
We currently have where we build a dynamic linq statement inside the where method
IRepository<Person> repository = new Repository<Person>();
var results = repository.GetQuery().Include("Names").Where([dynamic linq here]);
The problem with that approach is that we want to do include SelectMany and Select on the actual dynamic linq query. You cannot use the SelectMany inside a Where method unless you are actually going into sub properties of sub properties. We would like to do something like the following dynamic linq statement.
SelectMany("Names").Where("LastName.Contains(#0)", "Smith").Select("Person")
We solved this issue without having to use a extension method. We were able to use a similar query that works inside a Where method.
So instead of...
SelectMany("Names").Where("LastName.Contains(#0)", "Smith").Select("Person")
We were able to get the same result with the following query that can be inside a Where method.
Where.("Names.Select(LastName).Contains(#0)", "Smith)
Then when just had to add a Contains Aggregate to the Dynamic Linq library.
http://blog.walteralmeida.com/2010/05/advanced-linq-dynamic-linq-library-add-support-for-contains-extension-.html
The SelectMany had sent us off on a wild goose chase!
Checkout this nuget package: NinjaNye.SearchExensions
It enables you to do something like the following:
var repository = new Repository<Person>();
var results = repository.GetQuery().Search(p => p.LastName, "Smith");
Connected to sql this will produce something smilar to the following:
SELECT [Extent1].[Id] AS [Id],
... [other properties],
[Extent1].[LastName] AS [LastName]
FROM [dbo].[Person] AS [Extent1]
WHERE ([Extent1].[LastName] LIKE N'%Smith%')
The query is built using expression trees so the result is clean.
Check out the source code here:
https://github.com/ninjanye/SearchExtensions/
I have two Entity Framework 4 Linq queries I wrote that make use of a custom class method, one works and one does not:
The custom method is:
public static DateTime GetLastReadToDate(string fbaUsername, Discussion discussion)
{
return (discussion.DiscussionUserReads.Where(dur => dur.User.aspnet_User.UserName == fbaUsername).FirstOrDefault() ?? new DiscussionUserRead { ReadToDate = DateTime.Now.AddYears(-99) }).ReadToDate;
}
The linq query that works calls a from after a from, the equivalent of SelectMany():
from g in oc.Users.Where(u => u.aspnet_User.UserName == fbaUsername).First().Groups
from d in g.Discussions
select new
{
UnReadPostCount = d.Posts.Where(p => p.CreatedDate > DiscussionRepository.GetLastReadToDate(fbaUsername, p.Discussion)).Count()
};
The query that does not work is more like a regular select:
from d in oc.Discussions
where d.Group.Name == "Student"
select new
{
UnReadPostCount = d.Posts.Where(p => p.CreatedDate > DiscussionRepository.GetLastReadToDate(fbaUsername, p.Discussion)).Count(),
};
The error I get is:
LINQ to Entities does not recognize the method 'System.DateTime GetLastReadToDate(System.String, Discussion)' method, and this method cannot be translated into a store expression.
My question is, why am I able to use my custom GetLastReadToDate() method in the first query and not the second? I suppose this has something to do with what gets executed on the db server and what gets executed on the client? These queries seem to use the GetLastReadToDate() method so similarly though, I'm wondering why would work for the first and not the second, and most importantly if there's a way to factor common query syntax like what's in the GetLastReadToDate() method into a separate location to be reused in several different other LINQ queries.
Please note all these queries are sharing the same object context.
I think your better of using a Model Defined Function here.
Define a scalar function in your database which returns a DateTime, pass through whatever you need, map it on your model, then use it in your LINQ query:
from g in oc.Users.Where(u => u.aspnet_User.UserName == fbaUsername).First().Groups
from d in g.Discussions
select new
{
UnReadPostCount = d.Posts.Where(p => p.CreatedDate > myFunkyModelFunction(fbaUsername, p.Discussion)).Count()
};
and most importantly if there's a way to factor common query syntax like what's in the GetLastReadToDate() method into a separate location to be reused in several different places LINQ queries.
A stored procedure would probably be one way to store that 'common query syntax"...EF, at least 4.0, works very nicely with SP's.
Suppose I have a table Person(PersonID, Name, ....). Then I use EF to create a Entity model and then create DomainService based on Ria Service. At client side(sliverlight), I try to create a dynamic linq for filter function. What I did is:
q = EntityQuery<MyData.Person>
q = q.Where(p=> p.Name.Contains(NameVar));
That is fine. Then I have another two tables for phone:
Phone(PhoneID, PhoneNumber, ...)
PersonPhone(PersonID, PhoneID, ...)
Then I want to add filter to match PhoneNumber. How to write the linq query q like?
q = q.Where(p => p.PersonPhone.
Where(ph=>ph.PhoneNumber.Contains(PhoneVar)&& ph.PersonID == p.PersonID).Count()>0);
I can pass the compiliation, but when run the app, I got error:
Query operator 'Count' is not supported
How to resolve this problem?
This sounds like a good scenario for writing a custom query method on the server and invoking that method instead of the default query for Person. RIA Services only supports a subset of LINQ operations on the client, but you can use all LINQ operators on the server.
You need to use the QueryBuilder
Here's a sample
var qb = new QueryBuilder<Person>().Where(p => p.PersonPhone.Where(ph=>ph.PhoneNumber.Contains(PhoneVar)&& ph.PersonID == p.PersonID).Count()>0);
Then you can take qb and apply it to whatever query you like.
query = qb.ApplyTo(query);
By using Func<QueryBuilder<Person>> you can pass around your dynamic filter into common controls and etc. And when you invoke the function you'll get the current values from that ViewModel.