I want to use Second level Cache for my query with eager loading(query is below wrote in 3 different ways, i use query cache). I have standard one to many association. I set entity cache for parent, child, and association between parent and class. And the 2nd level cache doesn't work because i got exceptions.
I wrote my query in 3 different way:
Criteria:
session.CreateCriteria<DictionaryMaster>().SetFetchMode("DictionaryItems", FetchMode.Eager)
.SetResultTransformer(new DistinctRootEntityResultTransformer())
.SetCacheable(true).SetCacheMode(CacheMode.Normal)
.List<DictionaryMaster>().ToList();
When I invoked this query i got exception "Unable to perform find[SQL: SQL not available]"
I think that the problem exists because I use DistinctRootEntityResultTransformer transform. I will start create my custom transform class and I hope that will work.
Query over:
session.QueryOver<DictionaryMaster>().Fetch(x => x.DictionaryItems).Eager
.TransformUsing(new DistinctRootEntityResultTransformer())
.Cacheable().CacheMode(CacheMode.Normal)
.List<DictionaryMaster>().ToList();
Exception is the same as in Criteria.
Linq:
session.Query<DictionaryMaster>().Fetch(x => x.DictionaryItems).Cacheable().CacheMode(CacheMode.Normal).ToList();
Here error depends from the version of nhibernate in 3.1 a got this error https://nhibernate.jira.com/browse/NH-2587?page=com.atlassian.jira.plugin.system.issuetabpanels%3Achangehistory-tabpanel
but in 3.2 version i got this: https://nhibernate.jira.com/browse/NH-2856
Thanks in advance
sJHony I have found solution, but for me is more like workaround. Therefore if you know any other solution give me sign.
I utilize QueryOver without any transformation, the fault of this solution is that the query return elements equal amount of childs. Next I retrieve not multiplied list in memory using distinct.
This solution is ok, but when we add one more Fetch for query, then collection in object also be multiplied, that is why i modified collection type from IList(Bag) to ISet(Set).
Code looks like:
var queryCacheResult =
session.QueryOver<DictionaryMaster>()
.Fetch(x => x.DictionaryItems).Eager
.Cacheable().CacheMode(CacheMode.Normal)
.List<DictionaryMaster>().ToList();
return queryCacheResult.Distinct(new KeyEqualityComparer<DictionaryMaster>(x => x.Code)).ToList();
Related
In my controller method for the the index view I have the following line.
#students_instance = Student.includes(:memo_tests => {:memo_target => :memo_level})
So for each Student I eager-load all necessary info.
Later on in a .map block, I call the .where() method on one of the relations as shown below.
#all_students = #students_instance.map do |student|
...
last_pass = student.memo_tests.where(:result => true).last.created_at.utc
difference_in_weeks = ((last_pass.to_i - current_date.to_i) / 1.week).round
...
end
This leads to a single SQL query for each student. And since I have over 300+ students, leads to very slow load times and over 300+ SQL queries.
Am I right in thinking that this is caused by the .where() method. I think this because I have checked everything else and these are the two lines that cause all of the queries.
More importantly, is there a better way to do this that reduces these queries to a single query?
The moment you ask where, the statement is translated to a query. Normally, the result should be sql-cached...
Anyway, in order to be sure, you can instead add programming logic to your statement. That way, you are not requesting a NEW sql statement.
last_pass = student.memo_tests.map {|m| m.created_at if m.result}.compact.sort.last
EDIT
I see the OP's question does not require sorting... So, leaving the sorting out:
last_pass = student.memo_tests.map {|m| m.created_at if m.result}.compact.last
compact is required to remove nil results from the array.
I'm missing something simple - I do not want to access the results of this query in a view.
Here is the query:
#adm = Admin.where({:id => {"$ne" => params[:id].to_s},:email => params[:email]})
And of course when you inspect you get:
#adm is #<MongoMapper::Plugins::Querying::DecoratedPluckyQuery:0x007fb4be99acd0>
I understand (from asking the MM guys) why this is the case - they wished to delay the results of the actual query as long as possible, and only get a representation of the query object until we render (in a view!).
But what I'm trying to ascertain in my code is IF one of my params matches or doesn't match the result of my query in the controller so I can either return an error message or proceed.
Normally in a view I'm going to do:
#adm.id
To get the BSON out of this. When you try this on the Decorated Query of course it fails:
NoMethodError (undefined method `id' for #<MongoMapper::Plugins::Querying::DecoratedPluckyQuery:0x007fb4b9e9f118>)
This is because it's not actually a Ruby Object yet, it's still the query proxy.
Now I'm fundamentally missing something because I never read a "getting started with Ruby" guide - I just smashed my way in here and learned through brute-force. So, what method do I call to get the results of the Plucky Query?
The field #adm is set to a query as you've seen. So, to access the results, you'll need to trigger execution of the query. There are a variety of activation methods you can call, including all, first, and last. There's a little documentation here.
In this case, you could do something like:
adm_query = Admin.where({:id => {"$ne" => params[:id].to_s},:email => params[:email]})
#adm_user = adm_query.first
That would return you the first user and after checking for nil
if #adm_user.nil?
# do something if no results were found
end
You could also limit the query results:
adm_query = Admin.where( ... your query ...).limit(1)
Is there anyway to use NHibernate in such a way that it whould only execute the query/queries once the returned object of a query/statement is used.. just like EF doest it?
For most instances with EF it wont send and execute the actual query to the database until the returned object of a linq-"statement" is used.. for instance:
var x = for e in entities.MyTable
select e;
This aint executed yet!
Which meens that Im able to mofidy the x-objects "linq-query" however I like without actualt "pulling" any data from the database:
x = x.Where(i=>i.SomeThing = someThing);
Still aint executed!
x.ToList<MyTable>()
Now its executed!
But in NHibernate the query gets executed once the transaction gets closed or commited from what I have understod.. and in most cases thats done already in the repository. So you can't simply in any other place alter the query and then send it to the database. Cause the query is already sent and that whould mean that you later on only whould alter whats "displayed" from the result.
I might have gotten this al wrong so please correct me if I am wrong.
Huge thanks in advance!
You can try something like this using detached QueryOver
var query = QueryOver.Of<Customer>()
.Where(x => x.LastName == "Smith"); // query is not executed yet
query.GetExecutableQueryOver(session).List();
Good thing is that you can pass QueryOver objects and get it executed somewhere else.
In rails 3, I would like to do the following:
SomeModel.where(:some_connection_id => anArrayOfIds).select("some_other_connection_id")
This works, but i get the following from the DB:
[{"some_other_connection_id":254},{"some_other_connection_id":315}]
Now, those id-s are the ones I need, but I am uncapable of making a query that only gives me the ids. I do not want to have to itterate over the resulst, only to get those numbers out. Are there any way for me to do this with something like :
SomeModel.where(:some_connection_id => anArrayOfIds).select("some_other_connection_id").values()
Or something of that nautre?
I have been trying with the ".select_values()" found at Git-hub, but it only returns "some_other_connection_id".
I am not an expert in rails, so this info might be helpful also:
The "SomeModel" is a connecting table, for a many-to-many relation in one of my other models. So, accually what I am trying to do is to, from the array of IDs, get all the entries from the other side of the connection. Basicly I have the source ids, and i want to get the data from the models with all the target ids. If there is a magic way of getting these without me having to do all the sql myself (with some help from active record) it would be really nice!
Thanks :)
Try pluck method
SomeModel.where(:some => condition).pluck("some_field")
it works like
SomeModel.where(:some => condition).select("some_field").map(&:some_field)
SomeModel.where(:some_connection_id => anArrayOfIds).select("some_other_connection_id").map &:some_other_connection_id
This is essentially a shorthand for:
results = SomeModel.where(:some_connection_id => anArrayOfIds).select("some_other_connection_id")
results.map {|row| row.some_other_connection_id}
Look at Array#map for details on map method.
Beware that there is no lazy loading here, as it iterates over the results, but it shouldn't be a problem, unless you want to add more constructs to you query or retrieve some associated objects(which should not be the case as you haven't got the ids for loading the associated objects).
When I try to run this piece of logic, NHibernate comes back with an error stating it has no reference to "Site".
IQueryable<Product> query = this.RetrieveAll();
query = query.Where(x => x.Status == Product.Statuses.Approved || x.SiteProduct.Where(y => y.Site.ID == siteID).Count() > 0);
A little background.
Product has a One to Many Map to SiteProduct
SiteProduct has a One to Many Map to Site
Even a simpler version has issues it states it has no reference to ID:
IQueryable<Product> query = this.RetrieveAll();
query = query.Where(x => x.Status == Product.Statuses.Approved || x.SiteProduct.Where(y => y.ID > 0).Count() > 0);
Does NHibernate have issues with nesting "Where" statements within itself?
As for the table mappings, they appear to be correct since I can transverse all the way down and capture individual records at the bottom through lazy loading. Addition, Getting and Deleting records all works perfectly. I am just having problems with nesting my Linq query.
This would have been a lot easier if someone had an answer for me on this.
What I found out through trial and error...
Apparently through lazy loading it was not going back and loading the related tables I was referencing. This was causing a null error and giving me no reference to "Site" error.
When I changed the loading from lazy loading to eager loading, there error went away.
So the moral to this story is that if the reference to a table where you are trying to use your nested where statement is null, you will get this error.