Does NHibernate LINQ support ToLower() in Where() clauses? - linq

I have an entity and its mapping:
public class Test
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
}
public class TestMap : EntityMap<Test>
{
public TestMap()
{
Id(x => x.Id);
Map(x => x.Name);
Map(x => x.Description);
}
}
I'm trying to run a query on it (to grab it out of the database):
var keyword = "test" // this is coming in from the user
keyword = keyword.ToLower(); // convert it to all lower-case
var results = session.Linq<Test>
.Where(x => x.Name.ToLower().Contains(keyword));
results.Count(); // execute the query
However, whenever I run this query, I get the following exception:
Index was out of range. Must be non-negative and less than the size of the
collection. Parameter name: index
Am I right when I say that, currently, Linq to NHibernate does not support ToLower()? And if so, is there an alternative that allows me to search for a string in the middle of another string that Linq to NHibernate is compatible with? For example, if the user searches for kap, I need it to match Kapiolani, Makapuu, and Lapkap.

I had this happen recently. I can tell you that ToLower() does not work and that Contains() and StartsWith() do work and are not case sensitive. You can get the desired affect by using Contains() and StartsWith() directly.

There seems to be a lot of confusion around this subject.
The "old" Linq provider (for NHibernate 2.x) probably might not support this. If that's the case, it never will because it's not maintained anymore.
The new provider (included with NHibernate 3.x) does support it (although ToUpper and ToLower seem to be inverted, see http://groups.google.com/group/nhibernate-development/browse_thread/thread/a167216e466b3241)
Contains and StartsWith map to the LIKE operator in SQL. They are not case insensitive themselves; it's the collation that makes them case insensitive, so that depends on how your column/schema were created.
Update (2010-04-09): bug confirmed and patch submitted, see https://nhibernate.jira.com/browse/NH-2169
Update (2010-05-21): patch was applied on 2010-05-01 and works as expected now.

According to the comments in these two blog posts this functionality is not implemented yet.

You might want to confirm whether the database uses case sensitivity.
If it doesn't, then you don't need .ToLower()

The accepted answer mentions using Contains() and StartsWith() which are good. but wouldn't work in cases when you want to be sure both strings are the same.
Using "==" will suffice since it is also case-insensitive. So, you no longer need to use ToLower() nor ToUpper();

Related

Return subset of Redis Values matching specific property?

Let's say I have this kind of model:
public class MyModel
{
public long ID { get; set; }
public long ParentModelID { get; set; }
public long ReferenceID1 { get; set; }
public long ReferenceID2 { get; set; }
}
There are more attributes, but for examples sake, it is just this. There are around 5000 - 10000 rows of this model. Currently storing it in a Redis Set.
Is there an efficient way in REDIS to query only a subset of the whole Data Set? For example, in LINQ I can do:
allModels.Where(m => m.ParentModelID == my_id);
or
allModels.Where(m => m.ReferenceID1 == my_referenceid);
Basically, being able to search through the dataset without returning the whole dataset and performing the LINQ queries against that. Because querying and returning 10,000 rows to get only 100 is not efficient?
You can use an OHM (Object-Hash Mapper, like ORM) in your favorite language to achieve the LINQ-like behavior. There are quite a few listed under the "Higher level libraries and tools" section of the [Redis Clients page](https://redis.io/clients.
Alternatively, you can implement it yourself using the patterns described at https://redis.io/topics/indexes.
You can't use something like LINQ in Redis out of the box. Redis is just a key-value store, so it doesn't have the same principles or luxuries as a relational database. It doesn't have queries or relations, so something like LINQ just doesn't translate at all.
As a workaround, you could segment your data using different keys. Each key could reference a set that stores values with a specific range of reference Ids. That way you wouldn't need to retrieve all 10,000 items.
I would also recommend looking at hashes, this might be more appropriate than a set depending on your use case as they're better at storing complex data objects.

OData $orderby clause on collection property

I have the following classes :
public class Parent
{
public string ParentProp { get; set; }
public IEnumerable<Child> ManyChildren { get; set; }
}
public class Child
{
public string ChildName { get; set; }
public int Value { get; set; }
}
Say I have an OData operation defined which returns IEnumberable<Parent>. Can I write an $orderby clause which performs the following operation ('parents' is an IEnumerable<Parent>) :
parents.OrderBy(x => x.ManyChildren.Single(y => y.ChildName == "Child1").Value);
I know I can write custom actions (http://msdn.microsoft.com/en-us/library/hh859851(v=vs.103).aspx) to do this ordering for me, but I'd rather use an $orderby clause.
(The only SO question which asked something similar is a little dated - How can I order objects according to some attribute of the child in OData?)
As I tried is possible with nesting $orderby in $expand so will be:
odata/User?&$select=Active,Description,Name,UserId&$expand=Company($select=Active,Name,CreatedBy,CompanyId;$orderby=Active asc)
And what you get is somthing like:
ORDER BY [Project2].[UserId] ASC, [Project2].[C19] ASC
will order a company collection for each user separately.
I think in version OData Client for .NET 6.7.0 is supported, in release notes is writhing:
In query options
$id, $select, $expand(including nested query options)....
I see in version 6.1 that values for nested options exist and is in:
DataQueryOptions->SelectExpand->SelectExpandClasue->SelectedItems->ExpandNavigationItem->OrderByOption
but is not working.
I tried and with System.Web.OData 5.6 and all releated dependencies but seams is not working.
My conclusion:
Seams that is everiting prepared like DataQueryOptions exist nested orderby but is not working.
Like I find out standard seams is going in that direction.
https://issues.oasis-open.org/browse/ODATA-32
It depends on your OData service implementation. Which kind of service are you using? WCFDS, WebAPI, or the service you implement yourself?
Url parser do can parse the URL such as root/People?$orderby=Company/Name. The translator is implemented by service.
And I agree with the answer in related question: "it's not possible to do this with a navigation property that has a cardinality of many". Since it's has a cardinality of many, service cannot know which one should be used to sorting.

MVC3 editor template for multiple types

I have a model with some parameters that a User should be able to see but not edit and others they should be able to edit. The same is true of the Author. So, I used [UIHint("Author")] and [UIHint("User")] attributes and wrote a couple editor templates, like so:
#inherits System.Web.Mvc.WebViewPage
#if (ViewBag.RoleId > (int)Role.RoleEnum.Author)
{
#Html.TextBoxFor(m => m, new { disabled = "disabled" })
}
else
{
#Html.TextBoxFor(m => m)
}
This almost does what I want. I'd like to be able to apply these attributes to booleans and get check boxes - like the default EditorFor. I suppose I could make another template and use something like [UIHint("AuthorBool")], but I'm hoping to come up with something better.
Hi Oniel,
You could create separate ViewModels for each type of user and use the data annotation of [ReadOnly]. But then you get into the realms of large amounts of repetition.
Personally I would recommend that you create your own version of each data type and implement standard role based handling using additionalmetadata data annotations to customise. Okay bit of work to begin with but then massively re-usable and highly portable.
Example:
[UIHint("MyCustomTemplateControl")]
[AdditionalMetadata("DenyEditUnlessInRole", "Admin")]
public string MyName { get; set; }
or:
[UIHint("MyCustomTemplateControl")]
[AdditionalMetadata("DenyEditIfInRole", "StandardUser")]
public string MyName { get; set; }
You can perform a code based / database based lookup in a class somewhere else that your datatypes templates query to make a decision on whether a user/role should get read/edit access to this property.
Does this make sense?
As a third option, create an editortemplate for the entire object and only include those fields and field types you are interesting in exposing.
MVC is so flexible - I suppose in the end it depends on how DRY do you want to make your code.
Good luck!
Dan.

Linq dynamic queries for user search screens

I have a database that has a user search screen that is "dynamic" in that I can add additional search criteria on the fly based on what columns are available in the particular view the search is based on and it will allow the user to use them immediately. Previously I had been using nettiers for this database, but now I am programming a new application against it using RIA and EntFramework 4 and LINQ.
I currently have 2 tables that are used for this, one that fills the combobox with the available search string patterns:
LastName
LastName, FirstName
Phone
etc....
then I have an other table that splits those criteria out and is used in my nettiers algorithms. It works well, but I want to use LINQ..and it doesnt fit this model very well. Besides I think I can pare it down to just one table with linq...
using a format similar to this or something very close...
ID Criteria WhereClause
1 LastName 'Lastname Like '%{0}%'
now I know this wont fit specifically into a linq query..but I am trying to use a univeral syntax for clarity here...
the real where clause would look something like this: a=>a.LastName.Contains("{0}")
My first question is: Is that even possible to do? Feed a lambda in to a string and use it in a Linq Query?
My second question is: at one point when I was researching this before I found a linq syntax that had a prefix like it.LastName{0}
and I appear to have tried using it because vestiges of it are still in my test databases...but I dont know recall where I read about it.
Is anyone doing this? I have done some searches and found similar occurances but they mostly have static fields that are optional, not exactly the way I am doing it...
As for your first question, you can do this using Dynamic Linq as described by Scott Gu here
var query = Northwind.Products.Where("Lastname LIKE "test%");
I'm not sure how detailed your dynamic query needs to be, but when I need to do dynamic queries, I create a class to represent filter values. Then I pass that class to a search method on my repository. If the value for a field is null then the query ignores it. If it has a value it adds the appropriate filter.
public class CustomerSearchCriteria{
public string LastName { get; set; }
public string FirstName { get; set; }
public string PhoneName { get; set; }
}
public IEnumberable<Customer> Search(CustomerSearchCriteria criteria){
var q = db.Customers();
if(criteria.FirstName != null){
q = q.Where(c=>c.FirstName.Contains(criteria.FirstName));
}
if(criteria.LastName!= null){
q = q.Where(c=>c.LastName.Contains(criteria.LastName));
}
if(criteria.Phone!= null){
q = q.Where(c=>c.Phone.Contains(criteria.Phone));
}
return q.AsEnumerable();
}

Dynamic Linq Search Expression on Navigation Properties

We are building dynamic search expressions using the Dynamic Linq library. We have run into an issue with how to construct a lamba expression using the dynamic linq library for navigation properties that have a one to many relationship.
We have the following that we are using with a contains statement-
Person.Names.Select(FamilyName).FirstOrDefault()
It works but there are two problems.
It of course only selects the FirstOrDefault() name. We want it to use all the names for each person.
If there are no names for a person the Select throws an exception.
It is not that difficult with a regular query because we can do two from statements, but the lambda expression is more challenging.
Any recommendations would be appreciated.
EDIT-
Additional code information...a non dynamic linq expression would look something like this.
var results = persons.Where(p => p.Names.Select(n => n.FamilyName).FirstOrDefault().Contains("Smith")).ToList();
and the class looks like the following-
public class Person
{
public bool IsActive { get; set;}
public virtual ICollection<Name> Names {get; set;}
}
public class Name
{
public string GivenName { get; set; }
public string FamilyName { get; set; }
public virtual Person Person { get; set;}
}
We hashed it out and made it, but it was quite challenging. Below are the various methods on how we progressed to the final result. Now we just have to rethink how our SearchExpression class is built...but that is another story.
1. Equivalent Query Syntax
var results = from person in persons
from name in person.names
where name.FamilyName.Contains("Smith")
select person;
2. Equivalent Lambda Syntax
var results = persons.SelectMany(person => person.Names)
.Where(name => name.FamilyName.Contains("Smith"))
.Select(personName => personName.Person);
3. Equivalent Lambda Syntax with Dynamic Linq
var results = persons.AsQueryable().SelectMany("Names")
.Where("FamilyName.Contains(#0)", "Smith")
.Select("Person");
Notes - You will have to add a Contains method to the Dynamic Linq library.
EDIT - Alternatively use just a select...much more simple...but it require the Contains method addition as noted above.
var results = persons.AsQueryable().Where("Names.Select(FamilyName)
.Contains(#0", "Smith)
We originally tried this, but ran into the dreaded 'No applicable aggregate method Contains exists.' error. I a round about way we resolved the problem when trying to get the SelectMany working...therefore just went back to the Select method.

Resources