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开发者_Go百科 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.
精彩评论