I have some linq query like this :
from x in from dbcontext
join y in dbcontext on x.id equals y.id select new {x,y}
my problem is how I can send these kinds of query to server as an object here is my linq query is direct data-access I need to send them to my data-server but I need an object. how I can implement this ?
Badly. Linq query contains references to the context. You don't have the context on the client and even if you have it will be different instance on the server. Doing anything like that would require damn big effort. Also you are returning projection to anonymous type - another very complicated feature when doing it remotely.
This can be of course handled - WCF Data Services already did this. They have client side "proxy" of context, query is serialized as OData query string and expression tree is built from that string on the server side. They also supports projections but they don't support STEs. Try WCF Data Services.
If you don't like the idea of WCF Data Services you should expose a method for each such query on the server side and client must call that method remotely.
firstly, IIRC you can't serialize Expressions, so firstly take a look at this post
then something along the lines of the following:
public List<ContactDetails> GetAllContactDetails( List<Guid> ContactIDs, Func<List<ContactDetails>, IEnumerable<ContactDetails>> filter )
{
List<ContactDetails> result = new List<ContactDetails>();
// get contacts as usual, fill result
// ...
return filter.Invoke( result ).ToList();
}
Usage:
GetAllContactDetails( idList, ( result ) =>
from contact in result
where contact.DateOfBirth > DateTime.Now.AddYears( -10 )
select contact );
D.R
Since Expression Trees are not serializable, it cannot be easily done.
My data access layer is not built with EF, so my solution may or may not be helpful to you, but here it is anyway:
I parse the expression on client side to a self-made serializable expression (which has properties like "columns", "joins", "filters", etc), and on the serverside I create sql based on these expressions.
You can create expressions from them of course, and send them against an EF linq provider!
Related
Whenever we want to use IEnumerable extension methods instead IQueryable version, we have use AsEnumerable() method.
var list = context.Details.AsEnumerable().Where(x => x.Code == "A1").ToList();
Why DbSet used IQueryable version of methods Like(Where , Select ,...) by default when other version available?
You'd usually want to use the IQueryable form, so that the filtering is done on the database instead of locally.
The code you've got will pull all records down to the client, and filter them there - that's extremely inefficient. You should only use AsEnumerable() when you're trying to do something that can't be performed in the database - usually after providing a server-side filter. (You may be able to do a coarse filter on the server, then a more fine-grained filter locally - but at least then you're not pulling all the records...)
Because IQuaryable methods are translated into SQL by Entity Framework.But IEnumerable method are not.So if you use IEnumearable all the data will be fetched from DB which is not always what you want.
I'm trying to do the following:
var query =
(from a in session.Query<A>()
where a.BasicSearch(searchString) == true
select a);
But it keeps giving me this exception "System.NotSupportedException"!
Any idea how to solve this?
It is not possible to use user-defined functions in a LINQ query. The NHibernate linq provider does not 'know' how to translate your function into SQL.
LINQ to NHibernate works by inspecting the LINQ expression that you provide at runtime, and translating what it finds in this expression tree into a regular SQL expression. Here's a good article to get some background on expression trees: http://blogs.msdn.com/b/charlie/archive/2008/01/31/expression-tree-basics.aspx
You CAN reuse predicates like this in another way however, using the techniques discussed here. (I'm not sure if this works with NHibernate however.) IF it works it would look something like this:
// this could be a static method on class A
public static Expression<Func<A, bool>> BasicSearch(string criteria)
{
// this is just an example, of course
// NHibernate Linq will translate this to something like
// 'WHERE a.MyProperty LIKE '%#criteria%'
return a => criteria.Contains(a.MyProperty);
}
Usage:
from a in Session.Query<A>().Where(A.BasicSearch(criteria))
UPDATE: apparently there will be issues with NHibernate. See this blog post for a version that ought to work.
It is possible to call your own and SQL functions, but you have to make a wrapper for them so that NHibernate knows how to translate the C# to SQL.
Here's an example where I write an extension method to get access to SQL Server's NEWID() function. You would use the same techniques to get access to any other function on your database server, built-in or user-defined.
Some examples to extend NHibernate LINQ:
http://fabiomaulo.blogspot.se/2010/07/nhibernate-linq-provider-extension.html
https://nhibernate.jira.com/browse/NH-3301
Declare a BasicSearch extension method. Supposing your udf is on dbo:
using NHibernate.Linq;
...
public static class CustomLinqExtensions
{
[LinqExtensionMethod("dbo.BasicSearch")]
public static bool BasicSearch(this string searchField, string pattern)
{
// No need to implement it in .Net, unless you wish to call it
// outside IQueryable context too.
throw new NotImplementedException("This call should be translated " +
"to SQL and run db side, but it has been run with .Net runtime");
}
}
Then use it on your entities:
session.Query<A>()
.Where(a => a.SomeStringProperty.BasicSearch("yourPattern") == true);
Beware, trying to use it without referencing an entity in its usage will cause it to get evaluated with .Net runtime instead of getting it translated to SQL.
Adapt this BasicSearch example to whatever input types it has to handle. Your question was calling it directly on the entity, which does not allow your readers to know on how many columns and with which types it need to run.
Currently our website is facing a problem with slow response times (more than 1 min) when we query CRM from our website. We are using CRM 2011 though a web service. When we investigated we found that the time was spent at the point of querying CRM.
We have used the CrmSvcUtil.exe to generate our proxy classes that map to CRM entities. Then we create an instance of context and query CRM using LINQ with C#.
When we query, We load our parent object with LINQ to CRM and then we use LoadProperty to load the related children.
I would like to know if anyone out there using a different method of querying CRM, and if you have come across issues like this in your implementation.
I’ve included a simplified sample query below.
public void SelectEventById(Guid id)
{
var crmEventDelivery = this.ServiceContext.EventDeliverySet.FirstOrDefault(eventDelivery => eventDelivery.Id == id);
if (crmEventDelivery != null)
{
this.SelectCrmEventDeliveryWithRelationships(crmEventDelivery);
}
}
private void SelectCrmEventDeliveryWithRelationships(EventDelivery crmEventDelivery)
{
// Loading List of Venue Delivery on parent crmEventDelivery thats been passed
this.ServiceContext.LoadProperty(crmEventDelivery, Attributes.EventDelivery.eventdelivery_venuedelivery);
foreach (var venueDelivery in crmEventDelivery.eventdelivery_venuedelivery)
{
// Loading Venue on each Venue Delivery
ServiceContext.LoadProperty(venueDelivery, Attributes.VenueDelivery.venue_venuedelivery);
}
// Loading List of Session Delivery on parent crmEventDelivery thats been passed
this.ServiceContext.LoadProperty(crmEventDelivery, Attributes.EventDelivery.eventdelivery_sessiondelivery);
foreach (var sessionDelivery in crmEventDelivery.eventdelivery_sessiondelivery)
{
// Loading Presenters on each Session Delivery
ServiceContext.LoadProperty(sessionDelivery, Attributes.SessionDelivery.sessiondelivery_presenterbooking);
}
}
Like mentioned on the other answers your main problem is the number of web service calls. What no one mentioned is that you can retrieve many objects with a single call using query joins. So you could try something like:
var query_join = (from e in ServiceContext.EventDeliverySet
join v in ServiceContext.VenueDeliverySet on e.EventDeliveryId equals v.EvendDeliveryId.Id
join vn in ServiceContext.VenueSet on v.VenueDeliveryId equals vn.VenueDeliveryId.Id
join s in ServiceContext.SessionDeliverSet on e.EventDeliveryId equals s.EvendDeliveryId.Id
where e.EventDeliveryId == id // *improtant (see below)
select new { EventDelivery = e, VenueDelivery = v, Venue = vn, SessionDeliver = s }).ToList();
Then you can run a foreach on query_join and put it together.
***improtant: do not use the base Id property (e.Id), stick with e.EntityNameId.Value (don't know why but it took a while for me to figure it out. Id returns default Guid value "00000..").
Based on what you've provided this looks like a standard lazy-load issue, except my guess is that each lazy load is resulting in a web service call. This would be called a "chatty" service architecture. Your goal should be to make as few service calls as possible to retrieve data for a single request.
Calling to fill in details can seem like a good idea because you can re-use the individual service methods for cases where you only want data 1 or 2 levels deep, or all the way down, but you pay a steep performance penalty.
You would be better off defining a web service call that returns a complete object graph in scenarios like this. I don't know if/what you're using for an ORM layer within the CRM but if you make a specific call to fetch a complete graph of Deliveries then the ORM can eager-fetch the data into fewer SQL statements. Fewer calls to the web service (and subsequently fewer calls into the CRM's data store) should noticeably improve your performance.
So I can see why this might take a while. I think as everyone else have commented you are making quite a few web service calls. If you get a moment it would be interesting to know if the individual calls are slow or its just because you are making so many, I would suggest profiling this.
In any case I suspect you would get better performance by not using the strongly type entities.
I would suggest using a FetchXml query, this will allow you to build a Sql Xml-Style query. Basically you should be able to replace your many we bservice calls with a single call. The MSDN has an example, also check out the Stunnware FetchXml designer, Products > Stunnware Tools > Download and Evaluation. It was built for Crm 4 but supports virtually all the features you will need.
If you dont fancy that, you could also try a QueryExpression or OData, both of which should allow you to get your data in one hit.
After trying all the suggested tips in the other answers and doing further profiling, in our particular scenario with our use of CRM, and how it was set up - we decided to simply bypass it.
We ended up using some of the in-built views, this is not a recommended approach in the CRM documentation, but we really needed to achieve higher performance and the CRM approach in this instance was just in our way.
To anyone else reading this, see the other answers too.
Because the query does not know what fields will be needed later, all columns are returned from the entity when only the entity is specified in the select clause. In order to specify only the fields you will use, you must return a new object in the select clause, specifying the fields you want to use.
So instead of this:
var accounts = from acct in xrm.AccountSet
where acct.Name.StartsWith("Test")
select acct;
Use this:
var accounts = from acct in xrm.AccountSet
where acct.Name.StartsWith("Test")
select new Account()
{
AccountId = acct.AccountId,
Name = acct.Name
};
Check out this post more details.
To Linq or not to Linq
I want to dynamically query an object with System.Linq.Dynamic.
var selectData = (from i in data
select i).AsQueryable().Where("Name = #0","Bob1");//This works fine with a non-entity object
I know that we cannot project onto a mapped entity. I believe that is the reason this code fails
foreach (var item in rawQuery.ObsDataResultList)
{
var propertyData = (from i in item
select i).AsQueryable().Where("PropertyName = #0", "blah");
}//item is a Entity Complex Type
Error
Could not find an implementation of the query pattern for
source type 'ClassLibrary1.Model.bhcs_ObsData_2_Result'. 'Select' not
found.
Given the fact that I need to specify the PropertyName at runtime, I don't see any way to project with an anonymous type or a DTO.
I don't need to retain any of the Entity functionality at this point, I just need the data. Copying the data onto something that is queryable is a valid solution. So, is it possible to query entity framework with dynamic LINQ?
And here is the entity class header (the thing I'm trying to query, aka the item object)
[EdmComplexTypeAttribute(NamespaceName="MyDbModel", Name="blah_myQuery_2_Result")]
[DataContractAttribute(IsReference=true)]
[Serializable()]
public partial class blah_myQuery_2_Result : ComplexObject
{
First of all, let me clarify that System.Linq.Dynamic is not a full fledged Microsoft product. It is just a sample we release some time ago, and we don't thoroughly test different LINQ implementations to work correctly with it. If you are looking for a fully supported text-based query language for EF ObjectContext API you should take a look at Entity SQL instead.
Besides that, if you want to use System.Linq.Dynamic and you are ok with testing yourself that you don't hit anything that will block your application from working, then I'll try to see if I can help. I am going to need additional information since I am not sure I understand everything in your code snippets.
First of all I would like to understand, in your first example what is "data" and where did it come from? In your second snippet, what is "rawQuery" and where did it come from? Besdies, what is rawQuery.DataResultList and what is rawQuery.ObsDataResultList?
Also regarding your second snippet, it seems that you are trying to compose with query operators on top of an object that is not actually of a query type (although that doesn't explain the error you are getting given that you are calling AsQueryable the compiler should have complained before that bhcs_ObsData_2_Result is not an IEnumerable nor a non-generic IEnumerable).
In your propposed answer you are saying that you tried with ObjectResult and that seemed to help. Just be aware that ObjectResult is not a query object and therefore it won't allow you to build queries that get send to the server. In other words, any query operators that you apply to ObjectResult will be evaluated in memory and if you don't keep this in mind you may end up bringing all the data from that table into memory before you apply any filtering.
Query ObjectResult<blah_myQuery_2_Result> directly instead of the item blah_myQuery_2_Result. For example
var result = (from i in rawQuery.DataResultList
select i).AsQueryable().Where("CreatedDTM > #0", DateTime.Now.Subtract(new TimeSpan(30, 0, 0, 0)));
So I have the following scenario and I am not sure how to approach it.
In the app that we are building we have a ReferenceDataService which is used to load data via RIA serices. A query is built up on the client as an IQuerable and submitted to the server for retrieval. Now most of the reference queries that are submitted are identical and called multiple times, therefore I would like to service these queries from the entity cache instead.
Below is an example of the query expression that is generated and I have highlighted the area where the query changes. There are some scenarios where the query has additonal criteria but the majority probably dont.
Chime.DataModel.classification[]
.Where(c => ((value(Chime.Modules.Reference.Client.Agent.ReferenceDataLoader+<>c__DisplayClass20).includeSchema
*AndAlso c.class_code.StartsWith(value(Chime.Modules.Reference.Client.Agent.ReferenceDataLoader+<>c__DisplayClass20).schema))*
OrElse (Not(value(Chime.Modules.Reference.Client.Agent.ReferenceDataLoader+<>c__DisplayClass20).includeSchema)
AndAlso *c.parent_code.StartsWith(value(Chime.Modules.Reference.Client.Agent.ReferenceDataLoader<>c__DisplayClass20).schema))))*
.OrderByDescending(c => c.value_scheme_ind)
.ThenBy(c => c.sequence_number)
.ThenBy(c => c.class_label)
So what I would like to do is actually cache the query and if another comes in with identical criteria I can hit the cache. The problem I have is that the literals used in the query do not seem to be available therefore I cannot determin if one query is different from another. The schema code for example is nowhere to be found. It must be sent the the server at some point but I am unsure how I can get at it.
Does anyone know a way to do this or come across this before?
Dave
If you were using WCF Data Services, I would just say call ToString() on your IQueryable and it would return an exact URI of the query to be executed against the Data Service...and you could simply cache based on that string value.
As far as I know, RIA doesn't expose such hooks, so you'll have to rely on more traditional methods.
Implement an ExpressionVisitor that visits your IQueryable.Expression and computes a hash code for it.
You mentioned you can't see your constant string values in your expression tree. That's because they are not inlined yet into the expression tree and thus still exist as MemberAccessExpressions, not ConstantExpressions. To fix this, you can use a partial evaluating ExpressionVisitor. The source for such is given here
http://msdn.microsoft.com/en-us/library/bb546158.aspx
Look at the Evaluator class.