Complex queries in linq to nhibernate - linq-to-nhibernate

We are using accountability pattern for organizational structure. I using linq to nhibernate to find some departments and position but I have two problem.
var query =
Repository<Party>.Find(p => p.IsInternal == true)
.Where(p => p.Parents.Any(c => c.Parent.PartyId == id))
.Where(p =>
(
p.PartyType.PartyTypeId == (int)PartyTypeDbId.Department &&
_secretariat.Departments.Select(c => c.PartyId).Contains(p.PartyId)
)
||
(
p.PartyType.PartyTypeId == (int)PartyTypeDbId.Position &&
p.Children.Any(c =>
c.AccountabilityType.AccountabilityTypeId == (int)AccountabilityTypeDbId.TenurePersonOfPosition &&
((Person)c.Child).UserName != null)
)
);
First : I got 'Unhandled Expression Type: 1003' for this part of query : '_secretariat.Departments.Select(c => c.PartyId).Contains(p.PartyId)'
and I got Property not found 'UserName'
We have many complex queries i think we need to use stored procedure.
Sorry for bad Inglish!

One nice thing that you can do with LINQ is break your queries into multiple parts. Since you are building an expression tree that won't get executed until the results are enumerated, you don't have to do it all in one line (like SQL).
You can even make some reusable "filters" that you can apply to IQueryable. These filter functions accept an IQueryable as an argument, and return one as a result. You can build these as extension methods if you like (I like to).
As for your immediate problem, you may want to try a join on _secretariat instead of attempting a subquery. I've seen them work in scenarios where subqueries don't.

In addition to Lance's comments you might want to look at a compiled Linq query and breaking up some of the responsibilties to follow SOLID principles.

I've just also found out that there are issues with the Contains when containing Any linq methods. However, Any seems to work well within Any, hence:
_secretariat.Departments.Select(c => c.PartyId).Any(x => x == p.PartyId)

Related

Orchard CMS HQL Query Taxonomies : OR in WHERE condition

I am trying to filter the pages that a user sees by checking for common terms between the user and the page. Both the user and the page have a Taxonomy Field of the same type ("Category"), with terms "Standard" and "Premium".
If the category of the user matches with the category of the page, I want to display it, otherwise don't. This works fine with the following IHqlQuery on PagePart:
context.Query.Where(a => a.ContentPartRecord<TermsPartRecord>()
.Property("Terms", "terms"),
x => x.InG("TermRecord.Id", ids));
where ids is the list of term ids of the user.
Apart from the above criteria, I also want to display pages that have no terms attached. This works fine on its own by:
context.Query.Where(a => a.ContentPartRecord<TermsPartRecord>(),
x => x.IsEmpty("Terms")
The problem is when I try to combine the above two conditions. I have tried:
context.Query.Where(a => a.ContentPartRecord<TermsPartRecord>()
.Property("Terms", "terms"),
p => p.Or(x => x.InG("TermRecord.Id", ids), y => y.IsEmpty("Terms")));
The second condition in the Or statement doesn't work because the query is already inside the Terms collection.
I have also tried:
context.Query.Where(a => a.ContentPartRecord<TermsPartRecord>()
p => p.Or(x => x.InG("Terms.TermRecord.Id", ids), y => y.IsEmpty("Terms")));
Here, the first condition is wrong, as I can't access an element of the Terms list with "Terms.TermRecord". This is as far as my Hql capabilities go. Do you have any suggestions? Thank you in advance.
I'm afraid I'm not all that familiar Orchard's query APIs, I always found them tough to use for more complex queries. You could always use raw HQL.
select distinct civ.Id
from Orchard.ContentManagement.Records.ContentItemVersionRecord civ
join civ.ContentItemRecord ci
join ci.ContentType ct
left outer join ci.TermsPartRecord tpr
left outer join tpr.Terms terms
where ct.Name = 'Page' AND (terms.TermRecord.Id in (:ids) OR size(tpr.Terms) = 0)

How to access the data stored in this object?

I'm using BioPerl module to obtain a string from a set of parameters. I followed the HOWTO:Beginners page. The module apparently returns a hash object. How do I get the actual string out of the hash object?
use Bio::DB::GenBank;
use Data::Dumper;
my $gb = Bio::DB::GenBank->new(-format => 'Fasta',
-seq_start => 1,
-seq_stop => 251,
-strand => 1
-complexity => 1);
my $seq = $gb->get_Seq_by_acc('NG_016346');
my $sequence_string = lc($seq->seq());
my $seq_obj = Bio::Seq->new(-seq => $sequence_string,
-alphabet => 'dna' );
my $prot_obj = $seq_obj->translate;
print Dumper($prot_obj);
The data dumper prints the following:
$VAR1 = bless( {
'primary_seq' => bless( {
'length' => 83,
'_root_verbose' => 0,
'_nowarnonempty' => undef,
'seq' => 'RLCVKEGPWPAVEGTWSWG*HRPGSRACPRWGAPNSVQATSYTPSPTHAPFSVSPIPIC*MSLLEASCWPGSREDGARMSAGM',
'alphabet' => 'protein'
}, 'Bio::PrimarySeq' ),
'_root_verbose' => 0
}, 'Bio::Seq' );
How do I obtain 'seq' that is stored in $prot_obj?
I tried
print $prot_obj{'primary_seq'}{'seq'};
but it doesn't print anything. Data dumper printed the word bless. Maybe seq is a field of an object oriented variable.
The correct format for accessing object properties uses ->:
print $prot_obj->{'primary_seq'}->{'seq'};
I'm going to dispute the other answer, and say - the correct way to access object properties is not to do so, and use a method instead.
The reason for doing this is the whole point of OO. Which is to encapsulate chunks of your program, such that multiple developers can work with it concurrently, and the code scales because you can find where things are going wrong more easily.
This only works if you used published methods - the specified way of driving the object - because then you don't have to know what's going on behind the scenes. It also means the implementor is free to change what is going on - maybe simply validating, but maybe overloading or having different responses depending on another property within the object.
All this is subverted by direct access to object properties.
You shouldn't do it, even if perl will "let" you. Let's face it, perl will let you do many bad things.
Bio::PrimarySeq has a method call of seq. to retrieve the seq() attribute. Bio::Seq has an accessor for the primary sequence:
So:
$prot_obj -> seq();
I think would probably do it. (Although, the doc isn't exactly easy reading).
There is an accepted answer but I would also advise against poking around in the intervals of objects like that with the only exception being to see what kind of object is returned (or just use ref). Here is how I would approach the problem:
use 5.010;
use strict;
use warnings;
use Bio::DB::GenBank;
use Bio::Seq;
my $gb = Bio::DB::GenBank->new(
-format => 'Fasta',
-seq_start => 1,
-seq_stop => 251,
-strand => 1,
-complexity => 1
);
my $seq = $gb->get_Seq_by_acc('NG_016346');
my $seq_obj = Bio::Seq->new(
-id => $seq->id,
-seq => $seq->seq,
-alphabet => 'dna'
);
say join "\n", ">".$seq_obj->id, $seq_obj->translate->seq;
Running this gives you the translated FASTA record:
>gi|283837914:1-251
RLCVKEGPWPAVEGTWSWG*HRPGSRACPRWGAPNSVQATSYTPSPTHAPFSVSPIPIC*MSLLEASCWPGSREDGARMSAGM
The real benefit of using BioPerl is in combining the different classes together to solve problems with minimal (but also readable and reusable) code. There was also a minor typo in your code that would have been caught with strict and warnings pragmas enabled (that is my best advice).

Search in new Sitecore ContentSearch using whole words

I am using new Sitecore search, and the issue I ran into is having results come for words that have nothing to do with my search term.
For example, searching for "lies" will find "applies". And this is not what I am looking for.
This is an example of search I am doing (simplified). It is a direct LINQ check for "Contains" on the "Content" property of the SearchResultItem, and most likely not what I supposed to do. It is just happen to be that samples I find online are practically doing so.
Example of my code (simplified). In here I break down the search sentence to separate keywords. By the way, I am looking for a way to show full sentence match first.
using (var context = ContentSearchManager.GetIndex("sitecore_web_index").CreateSearchContext())
{
var results = context.GetQueryable<SearchResultItem>()
.Filter(i => i.Path.StartsWith(Home.Paths.FullPath))
.Filter(GetTermPredicate(Term));
// use results here
}
protected Expression<Func<SearchResultItem, bool>> GetTermPredicate(string term)
{
var predicate = PredicateBuilder.True<SearchResultItem>();
foreach (var tempTerm in term.Split(' '))
{
predicate = predicate.And(p => p.Content.Contains(tempTerm));
}
return predicate;
}
Thank you in advance!!
All right. I got help from Sitecore Support.
In my version of Sitecore I can use the following to acheive search for a whole word instead of partial:
instead of:
predicate = predicate.And(p => p.Content.Contains(tempTerm));
use
predicate = predicate.And(p => p.Content.Equals(tempTerm));
Issue solved.
Replace Filter in your code by Where, it should be fine,
here is an example :
var currentIndex = ContentSearchManager.GetIndex("sitecore_web_index");
using (var context = currentIndex.CreateSearchContext())
{
var predicate = PredicateBuilder.True();
foreach (var currentWord in term.Split(‘ ‘))
{
predicate = predicate.Or(x => x.Content.Contains(currentWord ));
}
var results = context.GetQueryable().Where(predicate).GetResults();
}
As Ahmed notes, you should use Where instead of Filter, since Filter has no effect on search rank. The classic use case for filters is to apply a facet chosen by the user without distorting the ordering of results, as would happen if you used a Where clause.
Filtering is similar to using Where to restrict the result list. Both methods will affect the result in the same
result list, but when you use a Filter the scoring/ranking of the search hits is not affected by the filters.
Developer's Guide to Item Buckets and Search
There's a good dicussion of when to use Filter on the Sitecore 7 team blog:
Making Good Part 4: Filters, Paging and I'm feeling lucky.
If you only want to search for whole words, you could prefix and postfix the searchterm with a space. Allthough this doesn't catch all situations.

Construct Completely Ad-hoc Slick Query

Pardon my newbieness but im trying to build a completely ad-hoc query builder using slick. From our API, I will get a list of strings that is representative of the table, as well as another list that represents the filter for the tables, munge then together to create a query. The hope is that I can take these and create the inner join. A similar example of what i'm trying to do would be JIRA's advanced query builder.
I've been trying to build it using reflection but I've come across so many blocking issues i'm wondering if this is even possible at all.
In code this is what I want to do:
def getTableQueryFor(tbl:String):TableQuery[_] = {
... a matcher that returns a tableQueries?
... i think the return type is incorrect b/c erasure?
}
def getJoinConditionFor:(tbl1:String, tbl2:String) => scala.slick.lifted.Column[Boolean] = (l:Coffees,r:Suppies) => {
...a matcher
}
Is the Following even possible?
val q1 = getTableQueryFor("coffee")
val q2 = getTableQueryFor("supply")
val q3 = q1.innerJoin.q2.on(getJoinCondition("coffee", "supply")
edit: Fixed grammar issue.

Subsonic Delete multiple records

I have a table which has a two fields, userid and degreeid. A user can have multiple degreeds in this table. When a user select their degree I want to delete any degree id already in the database but un-selected by user. How should do it? I try to use something like this with no luck.
repo.DeleteMany(x=>x.MeetingAttendeeUserID==userID && x.EducationDegreeID userDegreeList)
Thanks,
Lewis
Could you do something like this?
repo.DeleteMany(x =>
x.MeetingAttendeeUserId == userID &&
x.EducationDegreeID != selectedDegreeId
);
Edit: Or this.
repo.DeleteMany(x =>
x.MeetingAttendeeUserId == userID &&
userDegreeList.Contains(x.EducationDegreeID))
);
I have tried
SubSonicRepository<ReportDatum> repo = new SubSonicRepository<ReportDatum>(db);
repo.DeleteMany(x => x.ReportID == Convert.ToInt32(reportID));
and it does nothing, not even an error.
Addendum for someone that comes across this:
don't convert in the delete call, convert your variables beforehand.
int deleteKey = Convert.ToInt32(reportID)
SubSonicRepository<ReportDatum> repo = new SubSonicRepository<ReportDatum>(db);
repo.DeleteMany(x => x.ReportID == deleteKey);
and it fired fine.
I would recommend if you dont know Lamda expression. Create your own stored procedure and call use it.
This will not restrict you using lamda expression if you don't have time to learn it.
Ultimately you wanted to done your job.

Resources