I'm working with NHibernate 2 in a .Net project and I'm using the Linq2NHibernate provider.
This simple query
var result = from d in session.Linq<Document>()
where d.CreationYear == 2010
select d.ChildEntity).ToList();
throws an exception telling me that is impossible to cast ChildEntity type do Document type.
Why is that?
I also tried to translate it in query methods, having
session.Linq<Document>()
.where(d=>d.CreationYear == 2010)
.select(d=>d.ChildEntity)
.ToList();
Isn't the select method supposed to project an IQueryble into a IQueryble, beeing TResult!=T ?
Try this:
var result = (from d in session.Linq<Document>()
where d.CreationYear == 2010
select new ChildEntityType
{ /* here just do a simple assignments for all ChildEntityType fields
d.ChildEntity */ } ).ToList();
Yes, this could look quite stupid, but linq2nhibernate sometimes behave very strange, when you try to select just an object.
The old Linq provider is extremely limited and has been unmaintained for several years.
I suggest that you upgrade to the latest stable NHibernate (3.2), which has a much better (and integrated) Linq provider.
can you try this:
session.Linq<Document>()
.Where(d=>d.CreationYear == 2010)
.Select(d=>d.ChildEntity)
.ToList<T>(); //where T is typeof(ChildEntity)
Related
I have an EntityCollection ec in C# which has been populated with all Accounts.
Now I want another List or EntityCollection from ec which has all the accounts with status active.
I am using Linq for the same.
But both form of LINQ returns a an empty result while ec has 354 number of records
var activeCRMEC = (from cl in ec.Entities
where cl.Attributes["statecode"].ToString()=="0"
select cl);
OR
var activeCRMEC = ec.Entities.Where(x => x.Attributes["statecode"].ToString() == "0");
Each time the resultset is empty and I am unable to iterate over it. And 300 or so accounts are active, I have checked.
Same thing happens when I use some other attribute such as name etc.
Please be kind enough to point out my mistake.
You can Generate Early Bound Classes to write Linq Queries.
or Else
You can Write Linq Queries Using Late Bound Using OrganizationServiceContext Class.
For Your Reference:
OrganizationServiceContext OrgServiceCOntext = new OrganizationServiceContext(service);
var RetrieveAll = OrgServiceCOntext.CreateQuery("account").
ToList().Where(w => (w.GetAttributeValue<OptionSetValue>("statecode").Value ==0)).Select(s=>s);
I'll give you a few hints, and then tell you what I'm guessing your issue is.
First, use early bound entities. If you've never generated them before, use the earlybound generator, you'll save yourself a lot headaches.
Second, if you can't use early bound entities, use the GetAttribute() method on the Entity class. It'll convert types for you, and handle null reference issues.
Your LINQ expressions look to be correct, so either the ec.Entities doesn't have any entities in it that match the criteria of "statecode" equaling 0, or you possibly have some differed execution occurring on your IEnumerables. Try calling ToList() on the activeCRMEC immediately after the LINQ statement to ensure that is not your issue.
The statecode is an OptionSetValue, you should cast it in this way
((OptionSetValue)cl.Attributes["statecode"]).Value == 0
or
cl.GetAttributeValue<OptionSetValue>("statecode").Value == 0
Both ways are valid and you should ask for the Value that it is an int.
Hope this can help you.
Below is my code . Please review it .
1. bool isUnavailable = db.Deploys.Where(p =>
p.HostEnvironmentId == Guid.Parse(host.ID) &&
p.Status == (int)DeployStatus.Deploying).AsEnumerable().Any();
This one works.
The following statements doesn't work.
2. bool isUnavailable = db.Deploys.Where(p =>
p.HostEnvironmentId == Guid.Parse(host.ID) &&
p.Status == (int)DeployStatus.Deploying).Any();//Error
The Exception is
An exception of type 'System.NotSupportedException' occurred in
Microsoft.Data.Services.Client.DLL but was not handled in user code
Additional information: The method 'Any' is not supported.
3. bool isUnavailable = db.Deploys.Where(p =>
p.HostEnvironmentId.ToString() == host.ID &&
p.Status == (int)DeployStatus.Deploying).AsEnumerable().Any();//Error
The Exception is
An exception of type 'System.NotSupportedException' occurred in
Microsoft.Data.Services.Client.DLL but was not handled in user code
Additional information: The expression (([10007].HostEnvironmentId.ToString() ==
"b7db845b-cec4-49af-8f4b-b419a4e44331") And ([10007].Status == 90)) is not supported.
The Deploys Class is the model which is built in the client proxy class of WCF Data service. I was using "add service reference" to create WCF client proxy class.
But as to the Generic List,
Supposed below code. it will works fine.
4.bool b=servers.Where(d =>
d.status == (int)Enums.ServerStatus.Deploying ||
d.status == int)Enums.ServerStatus.Unavailable).Any();
My question is
Why same way used in different Class got different result .(See the method 2 and method 4).
Why 2 and 3 don't work.
Hope someone can help me . Thanks
LINQ has a concept of 'providers'. When working with LINQ over different data sources, different things need to happen for identical LINQ queries depending on the data source.
For example, when you want to use LINQ to query a database, the LINQ query needs to be converted to an SQL query. When the data source is OData, the query needs to be converted to a URL. There are different providers for each, and each provider supports a different subset of LINQ operators and other language constructs. LINQ-to-SQL, Entity Framework and LINQ-to-NHibernate are three popular LINQ providers for database access.
In your case, you are using WCF Data Services which includes a LINQ provider for OData. Since in OData there is no way to express the .Any() LINQ operator, attempting to use it in a query with that provider throws an exception. By using .AsEnumerable() you're essentially saying to stop using the OData LINQ provider at that point and start using the LINQ-to-Objects provider (which isn't technically a provider, but conceptually you can think of it as one). That means only what comes before .AsEnumerable() will be converted to an OData query, causing to retrieve all the Deploy entities that match the .Where(), and after they have all been transferred to the client, the client will perform the .Any() by checking the number of Deploy entities it has received. This of course is bad if there are many such entities, it will cause unwanted transfer of data over the network when all you wanted is the server side (database probably) to check if there are any. Unfortunately, .Any() is not supported by OData 1.0 (I don't know about OData 2.0).
Also, OData may not support .ToString() either. You may need to compare the Guid structures directly, i.e. create a local variable that contains the GUID value you want to compare:
var g = Guid.Parse("b7db845b-cec4-49af-8f4b-b419a4e44331")`
And then in the query compare the GUIDs like so:
x.HostedEnvironment == g
I'm trying to evaluate NHibernate.LINQ 1.0 without actually writing any code. Ayende has admitted that this version of LINQ support is subpar compared to EF, but for the life of me I can't seem to find a page that explains what's supported and unsupported in this implementation. For example, can I use Skip & Take? What can I not use?
You can check LINQ for NHibernate examples to see tests done by Ayende himself on what's implemented and what's not for this provider.
Some of those generally supported:
Anonymous type creation. new { Person = x.Name }
First(). query.First()
FirstOrDefault(). query.FirstOrDefault()
Single(). query.Single()
SingleOrDefault(). query.SingleOrDefault()
Aggregate(). query.Aggregate((x1,x2) => x1)
Contains(). query.Where(x => x.Name.Contains("Foo"))
StartsWith().
EndsWith().
Substring(). where db.Methods.Substring(e.FirstName, 1, 2) == "An"
Sub-queries. query.Where(x => x.Company.Id == 4)
Count(). query.Where(x => x.Relatives.Count > 0)
Any(). query.Any()
Take(). query.Take(10)
Skip(). query.Take(10).Skip(4)
OrderBy(). orderby x.Name descending
Replace(). AfterMethod = e.FirstName.Replace("An", "Zan"),
CharIndex(). where db.Methods.CharIndex(e.FirstName, 'A') == 1
IndexOf(). where e.FirstName.IndexOf("An") == 1
Problematic:
Group by
Joins
One of my own examples:
query = NSession.Session.Linq<Catalog>()
.Where(acc => acc.Company.Status == "A")
.Where(acc => acc.Id.StartsWith("12-536"))
.Where(acc => acc.Id.EndsWith("92") || acc.Id.EndsWith("67"))
.Take(10).OrderBy(acc => acc.Title);
If you're production application is using the latest stable build 2.1.2.4 like I am, you're stuck with what the NHibernate.Linq provider gives us until NHibernate 3.0 (trunk) gets a stable release and we feel safe enough to use it on major applications. Until then, I'm more than happy with a mixture of NHibernate.Linq and HQL.
The basic test of whether NHibernate can work with a Linq statement is whether you can serialize that statement's expression tree, then deserialize it in a different process and get the right answer. That means no external closures; the lambda must work only with what it creates or is given as a parameter.
Linq2NH 1.0, IIRC, also chokes when using members of the class that are not mapped, so if, for instance, you have a read-only calculated property like a special weighted or rolling average, you must map it to a DB column in order to reference it in the lambda (or recreate the logic in the lambda). This is because the expression tree will eventually be boiled down into SQL (through one of NH's intermediates; in 2.x it's ICriteria, in 3.x it's HQL) and if NH cannot take an expression and convert it 1:1 into a SQL expression that will evaluate successfully, it's just not going to work.
There is one special case: Linq2NH, IIRC, is smart enough to turn an IList.Contains() expression into an IN clause. The list must be defined within the lambda (like new[]{"1","2"}.Contains(m.ID)).
The blog post from Ayende is from May this year. A lot of things changed.
The NHiberante. Linq 1.0 linq provider is deprecated since about a year because of the new linq provider in the NHibernate Trunk. The new linq provider is not completely finished yet, but already very complete and usable for much more than the old linq provider. Things that do not work with the new linq provider are considered bugs and will be solved some day when reported.
You can use skip and take with the old and new linq provider. The current list of known issues can be found on NHibernate Jira. Other issues are unknown and all other features are already supported.
I have been trying to use dynamic LINQ to Entity in my application for specifying the OrderBy attribute at runtime. However when using the code as described in the majority of documentation:
var query = context.Customer.OrderBy("Name");
I received the following exception:
System.Data.EntitySqlException: 'Name' could not be resolved in the current scope or context. Make sure that all referenced variables are in scope, that required schemas are loaded, and that namespaces are referenced correctly.
After much searching I found this MSDN page:
http://msdn.microsoft.com/en-us/library/bb358828.aspx
Which included the following code example:
ObjectQuery<Product> productQuery2 = productQuery1.OrderBy("it.ProductID");
This prompted me to change my code to the following:
var query = context.Customer.OrderBy("it.Name");
After this the code works perfectly. Would anyone be able to confirm that this is indeed the correct way to get OrderBy working with LINQ to Entity? I can’t believe that the framework would have been implemented in this way, perhaps I have overlooked something?
Thanks, Matt
The it.Name syntax is ESQL and is indeed specific to the EF. There are good reasons to use this sometimes (e.g., collation specifiers), but it's not what I normally do.
Usually I use standard LINQ expressions:
var query = context.Customer.OrderBy(p => p.Name);
You can also use System.Linq.Dynamic, if you download it from Code Gallery, and then your original query:
var query = context.Customer.OrderBy("Name");
...will work.
No nice way, so far
My answer to this question was to create a stored procedure which has parameter to control sorting.
Okay, so I'm doing my first foray into using the ADO.NET Entity Framework.
My test case right now includes a SQL Server 2008 database with 2 tables, Member and Profile, with a 1:1 relationship.
I then used the Entity Data Model wizard to auto-generate the EDM from the database. It generated a model with the correct association. Now I want to do this:
ObjectQuery<Member> members = entities.Member;
IQueryable<Member> membersQuery = from m in members select m;
foreach (Member m in membersQuery)
{
Profile p = m.Profile;
...
}
Which halfway works. I am able to iterate through all of the Members. But the problem I'm having is that m.Profile is always null. The examples for LINQ to Entities on the MSDN library seem to suggest that I will be able to seamlessly follow the navigation relationships like that, but it doesn't seem to work that way. I found that if I first load the profiles in a separate call somehow, such as using entities.Profile.ToList, then m.Profile will point to a valid Profile.
So my question is, is there an elegant way to force the framework to automatically load the data along the navigation relationships, or do I need to do that explicitly with a join or something else?
Thanks
Okay I managed to find the answer I needed here http://msdn.microsoft.com/en-us/magazine/cc507640.aspx. The following query will make sure that the Profile entity is loaded:
IQueryable<Member> membersQuery = from m in members.Include("Profile") select m;
I used this technique on a 1 to many relationship and works well. I have a Survey class and many questions as part of that from a different db table and using this technique managed to extract the related questions ...
context.Survey.Include("SurveyQuestion").Where(x => x.Id == id).First()
(context being the generated ObjectContext).
context.Survey.Include<T>().Where(x => x.Id == id).First()
I just spend 10mins trying to put together an extention method to do this, the closest I could come up with is ...
public static ObjectQuery<T> Include<T,U>(this ObjectQuery<T> context)
{
string path = typeof(U).ToString();
string[] split = path.Split('.');
return context.Include(split[split.Length - 1]);
}
Any pointers for the improvements would be most welcome :-)
On doing a bit more research found this ... StackOverflow link which has a post to Func link which is a lot better than my extension method attempt :-)