Is it possible to configure NHibernate to issue the NOEXPAND hint when it executes a select statement against an indexed view? SQL Server always skips the views and goes straight to the base tables when executing queries unless the hint is used.
Here is a hack I tried and it worked. Just added (NOEXPAND) to the "table" name.
<class name="ClassName" mutable="false" table="vw_ViewName (NOEXPAND)">
...
</class>
Related
In SSMS and MySQLWorkbench a view is the SQL that generates a result set. In Access those are called queries. Is a view the same as a query?
A view is essentially a stored/predefined query. Depending on the database in question, views may additionally have indexes defined against them, have referential integrity defined on them, and/or be materialized (pre-queried and persisted to disk).
Looking at the liquibase documention http://www.liquibase.org/documentation/changes/create_index.html, CIC is not possible with create index, as liquibase doesn't have a tag to specify concurrent option.
Is there a way to create index concurrently with liquibase?
You can specify runInTransaction as false to create the index concurrently.
Creating a concurrent index must be done with the arbitrary sql change:
<changeSet runInTransaction="false" id="10-add-widgets-kind-index" author="username">
<sql dbms="postgresql">
CREATE INDEX CONCURRENTLY
IF NOT EXISTS idx_widgets_kind
ON widgets(kind)
</sql>
</changeSet>
This is a combination of a_horse_with_no_name's comment and TheDude's answer.
The previous answers do the job. I would like to offer an alternative that doesn't directly answer the OP's question, but does offer a solution with the same end result with some added advantages. I feel it is good to show other options for people that stumble upon this answer like I did.
In order to create the index using only Liquibase, you would need to use the <sql> tag. I caution against this as it can cause undesired consequences in the event that you use a different database for any reason (development, evaluation, testing, etc). The sql statement will be skipped and you can be left thinking that the index was added when in reality it was not.
Additionally, this can lead to a less controlled migration, assuming you are running this on a production system without taking it down for maintenance and the migration being part of the build process.
I would propose creating the index directly on Postgres and adding the index migration normally using Liquibase and a precondition check.
First, add the index manually:
CREATE INDEX CONCURRENTLY widgets_kind_idx ON widgets (kind);
And then add to your Liquibase changeSet:
<changeSet id="10-add-widgets-kind-index" author="username">
<preConditions onFail="MARK_RAN">
<not>
<indexExists indexName="widgets_kind_idx" />
</not>
</preConditions>
<createIndex tableName="widgets" indexName="widgets_kind_idx">
<column name="kind" />
</createIndex>
</changeSet>
This offers the ability to add the index in any manner desired and keeps your Liquibase migrations in a known state. A fresh database being setup would not require the CONCURRENTLY keyword.
If one would want to insert into a view, what would be required to setup on NHibernate to allow this.
Neither
<generator class="identity" />
nor
<generator class="native" />
allows insert.
Error I get when I try this is either "Null id" or "Null identifier".
You can not insert, update or delete from a view even with regular SQL commands, nor with NHiberanate. Views are designed for read only purposes.
You should model your class from the original tables in a similar fashion as the view and then you could do any CRUD operation on it.
I have never done this but have you tried assigned:-
<generator class="assigned" />
Any modifications, including UPDATE, INSERT, and DELETE statements,
must reference columns from only one base table.
See here MSDN for more info
And there is one more thing if you use assigned, you have to explicitly specify to NHibernate if the object should be saved or updated by calling either the Save() or Update() method of the ISession.
I have two entities with many-to-many relationship defined on them.
<set name="TreasuryCodes" table="ServiceProviderAccountTreasuryCode" lazy="true" cascade="all">
<key column="ServiceProviderAccountId" />
<many-to-many column="TreasuryCodeId" class="TreasuryCode" />
</set>
<set name="ServiceProviderAccounts" table="ServiceProviderAccountTreasuryCode" lazy="true" inverse="true" cascade="all">
<key column="TreasuryCodeId" />
<many-to-many column="ServiceProviderAccountId" class="ServiceProviderAccount" />
</set>
Now I want to delete all ServiceProviderAccounts by ServiceProviderId. I write this code:
public void DeleteAllAccount(int serviceProviderId)
{
const string query = "delete ServiceProviderAccount spa where spa.ServiceProvider.Id = :serviceProviderId";
repository.Session.CreateQuery(query)
.SetInt32("serviceProviderId", serviceProviderId)
.ExecuteUpdate();
repository.Session.Flush();
}
and I receive this exception:
Test method Test.ServiceRepositoryTest.DeleteAllAccountTest threw exception:
NHibernate.Exceptions.GenericADOException: could not execute update query[SQL: delete from ServiceProviderAccount where ServiceProviderId=?] ---> System.Data.SqlClient.SqlException: The DELETE statement conflicted with the REFERENCE constraint "FKBC88A84CB684BF79". The conflict occurred in database "Test", table "dbo.ServiceProviderAccountTreasuryCode", column 'ServiceProviderAccountId'.
The statement has been terminated.
I'm confused, as I have defined cascade on the entity, shouldn't nhibernate remove rows from ServiceProviderAccountTreasuryCode?
UPDATE
ok, looks like ExecuteUpdate is not looking for NHibernate cascade, probably because it's not loading entities before deleting it? Anyway is there any other way to delete from ServiceProviderAccountTreasuryCode table and then from ServiceProviderAccounts via HQL? I know I can use cascades on database, but I want to avoid that. What I want is to delete rows from many-to-many association table by HQl. Is it possible? Or I should use plain SQL?
looks like you have a referential integrity problem i.e a foregin key relation ship where the id that you are deleting is being referenced somewhere else and that table will end up referencing nothing. if that is what you want to do then you can run the Truncate command but I am not sure why you will do that..
I would suggest you do a normal delete i.e using the nhibernate session and Linq like below:
foreach(var sessionProvider in Session.Linq<ServiceProviderAccount >().Where(x=>x.ServiceProvider.Id==servinceProviderId))
Session.Delete(sessionProvider);
Now note this is not at all a bad way to do your deletion as they are not fired against the dB immediately and is part of the Session till your transaction is committed and this should handle your referential integrity problems if your mappings are defined crrectly.
Hope this works..
Looks like it doesn't obey the cascading. HQL batch operations for update/delete is relatively new, and translate more or less directly to SQL. I believe that you must keep track of the related tables as well.
If you only delete single entities then the batch-delete doesn't do you much good. In order for NHibernate to actually take cascading into account, it must load the actual entitity, which you don't with your example.
I asked a similar question, the answer I got might interest you
Remove entity in NHibernate only by primary key
If a "WITH NOLOCK" query hint is used on a View in SQL Server, does it propagate that hint to the view definition itself, even if NOLOCK is NOT used for the raw tables in the View definition? The reason to need this is that sometimes the support staff wants to do huge time-consuming queries but would rather not force this lock on all queries using the view within the application itself.
Yes, NOLOCK will propagate to the tables used by the view definition (at least in SQL Server 2005).
See Table Hints in MSDN:
In SQL Server 2005, all lock hints are propagated to all the tables and views that are referenced in a view. Also, SQL Server performs the corresponding lock consistency checks.
However,
If a table contains computed columns and the computed columns are computed by expressions or functions accessing columns in other tables, the table hints are not used on those tables. This means the table hints are not propagated. For example, a NOLOCK table hint is specified on a table in the query. This table has computed columns that are computed by a combination of expressions and functions that access columns in another table. The tables referenced by the expressions and functions do not use the NOLOCK table hint when accessed.
If you're using indexed views you might want to read a bit more as there are some special cases there too.
Also see View Resolution for more info.
Just to supplement Rory's excellent answer.
He writes "Yes, NOLOCK will propagate to the tables used by the view definition (at least in SQL Server 2005)."
In fact this will work in SQL 2000 as well.
From BOL:
Because select_statement uses the SELECT statement, it is valid to use and hints as specified in the FROM clause. For more information, see FROM and SELECT.