NHibernate stops if unique constraint has been violated previously - nhibernate

I have a tiny problem with NHibernate and I can't figure out why. Every time I debug or profile the application and I accidently violate a unique constraint NHibernate just won't run any more multiqueries (I'll leave the exception stack trace till last). The flow is this. Everything works fine and then:
Violation of UNIQUE KEY constraint
'UQ__workday__572F4CF4753864A1'.
Cannot insert duplicate key in object
'dbo.workday'. The statement has been
terminated.
Description: An unhandled exception
occurred during the execution of the
current web request. Please review the
stack trace for more information about
the error and where it originated in
the code.
Exception Details:
System.Data.SqlClient.SqlException:
Violation of UNIQUE KEY constraint
'UQ__workday__572F4CF4753864A1'.
Cannot insert duplicate key in object
'dbo.workday'. The statement has been
terminated.terminated.
If I now try to run the same code that executes the query:
var query1 = QueryOver.Of<Invoice>()
.Fetch(x => x.Company).Eager
.Fetch(x => x.Workdays).Eager
.Where(x => x.Id == invoiceId);
var query2 = QueryOver.Of<Invoice>()
.Fetch(x => x.Company).Eager
.Fetch(x => x.Products).Eager
.Where(x => x.Id == invoiceId);
var result = Session.CreateMultiCriteria()
.Add(query1)
.Add(query2)
.List();
var invoice = ((IList) result[0])[0] as Invoice;
if (invoice != null) {
invoice.CalculateTotals();
}
return invoice;
That code generates the following statement
SELECT this_.invoice_id as invoice1_10_2_,
this_.invoice_number as invoice2_10_2_,
this_.invoice_prefix as invoice3_10_2_,
this_.start_date as start4_10_2_,
this_.end_date as end5_10_2_,
this_.period as period10_2_,
this_.km as km10_2_,
this_.km_price as km8_10_2_,
this_.hour_price as hour9_10_2_,
this_.gst as gst10_2_,
this_.customer_id as customer11_10_2_,
this_.printed as printed10_2_,
this_.created_at as created13_10_2_,
this_.created_by as created14_10_2_,
this_.updated_at as updated15_10_2_,
this_.updated_by as updated16_10_2_,
this_.deleted_at as deleted17_10_2_,
this_.deleted_by as deleted18_10_2_,
this_.company_id as company19_10_2_,
workdays2_.invoice_id as invoice10_4_,
workdays2_.workday_id as workday1_4_,
workdays2_.workday_id as workday1_15_0_,
workdays2_.created_at as created2_15_0_,
workdays2_.created_by as created3_15_0_,
workdays2_.updated_at as updated4_15_0_,
workdays2_.updated_by as updated5_15_0_,
workdays2_.quantity as quantity15_0_,
workdays2_.unit_price as unit7_15_0_,
workdays2_.day as day15_0_,
workdays2_.description as descript9_15_0_,
workdays2_.invoice_id as invoice10_15_0_,
company3_.company_id as company1_12_1_,
company3_.created_at as created2_12_1_,
company3_.created_by as created3_12_1_,
company3_.updated_at as updated4_12_1_,
company3_.updated_by as updated5_12_1_,
company3_.name as name12_1_,
company3_.bankgiro_nr as bankgiro7_12_1_,
company3_.invoice_prefix as invoice8_12_1_,
company3_.moms_reg_nr as moms9_12_1_,
company3_.plus_giro_nr as plus10_12_1_,
company3_.contact_person as contact11_12_1_,
company3_.email as email12_1_,
company3_.mobile as mobile12_1_,
company3_.phone as phone12_1_,
company3_.fax as fax12_1_
FROM [invoice] this_
left outer join [workday] workdays2_
on this_.invoice_id = workdays2_.invoice_id
left outer join [company] company3_
on this_.company_id = company3_.company_id
WHERE this_.invoice_id = 351 /* #p0 */
SELECT this_.invoice_id as invoice1_10_2_,
this_.invoice_number as invoice2_10_2_,
this_.invoice_prefix as invoice3_10_2_,
this_.start_date as start4_10_2_,
this_.end_date as end5_10_2_,
this_.period as period10_2_,
this_.km as km10_2_,
this_.km_price as km8_10_2_,
this_.hour_price as hour9_10_2_,
this_.gst as gst10_2_,
this_.customer_id as customer11_10_2_,
this_.printed as printed10_2_,
this_.created_at as created13_10_2_,
this_.created_by as created14_10_2_,
this_.updated_at as updated15_10_2_,
this_.updated_by as updated16_10_2_,
this_.deleted_at as deleted17_10_2_,
this_.deleted_by as deleted18_10_2_,
this_.company_id as company19_10_2_,
products2_.invoice_id as invoice10_4_,
products2_.product_id as product1_4_,
products2_.product_id as product1_13_0_,
products2_.created_at as created2_13_0_,
products2_.created_by as created3_13_0_,
products2_.updated_at as updated4_13_0_,
products2_.updated_by as updated5_13_0_,
products2_.quantity as quantity13_0_,
products2_.profit_rate as profit7_13_0_,
products2_.unit_price as unit8_13_0_,
products2_.description as descript9_13_0_,
products2_.invoice_id as invoice10_13_0_,
company3_.company_id as company1_12_1_,
company3_.created_at as created2_12_1_,
company3_.created_by as created3_12_1_,
company3_.updated_at as updated4_12_1_,
company3_.updated_by as updated5_12_1_,
company3_.name as name12_1_,
company3_.bankgiro_nr as bankgiro7_12_1_,
company3_.invoice_prefix as invoice8_12_1_,
company3_.moms_reg_nr as moms9_12_1_,
company3_.plus_giro_nr as plus10_12_1_,
company3_.contact_person as contact11_12_1_,
company3_.email as email12_1_,
company3_.mobile as mobile12_1_,
company3_.phone as phone12_1_,
company3_.fax as fax12_1_
FROM [invoice] this_
left outer join [product] products2_
on this_.invoice_id = products2_.invoice_id
left outer join [company] company3_
on this_.company_id = company3_.company_id
WHERE this_.invoice_id = 351 /* #p1 */
I get the following really frustrating exception. Actually from now on every query is a timeout and the application needs to be restarted before I can execute anything. Sometimes it doesn't even help to restart it.
Does anyone know what is up with that?
at
System.Data.SqlClient.SqlConnection.OnError(SqlException
exception, Boolean breakConnection)
at
System.Data.SqlClient.SqlInternalConnection.OnError(SqlException
exception, Boolean breakConnection)
at
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
at
System.Data.SqlClient.TdsParser.Run(RunBehavior
runBehavior, SqlCommand cmdHandler,
SqlDataReader dataStream,
BulkCopySimpleResultSet
bulkCopyHandler, TdsParserStateObject
stateObj) at
System.Data.SqlClient.SqlDataReader.ConsumeMetaData()
at
System.Data.SqlClient.SqlDataReader.get_MetaData()
at
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader
ds, RunBehavior runBehavior, String
resetOptionsString) at
System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior
cmdBehavior, RunBehavior runBehavior,
Boolean returnStream, Boolean async)
at
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior
cmdBehavior, RunBehavior runBehavior,
Boolean returnStream, String method,
DbAsyncResult result) at
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior
cmdBehavior, RunBehavior runBehavior,
Boolean returnStream, String method)
at
System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior
behavior, String method) at
System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior
behavior) at
System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader()
at
NHibernate.AdoNet.AbstractBatcher.ExecuteReader(IDbCommand
cmd) in
d:\CSharp\NH\nhibernate\src\NHibernate\AdoNet\AbstractBatcher.cs:line
247 at
NHibernate.Impl.MultiCriteriaImpl.GetResultsFromDatabase(IList
results) in
d:\CSharp\NH\nhibernate\src\NHibernate\Impl\MultiCriteriaImpl.cs:line
209 at
NHibernate.Impl.MultiCriteriaImpl.DoList()
in
d:\CSharp\NH\nhibernate\src\NHibernate\Impl\MultiCriteriaImpl.cs:line
171 at
NHibernate.Impl.MultiCriteriaImpl.ListIgnoreQueryCache()
in
d:\CSharp\NH\nhibernate\src\NHibernate\Impl\MultiCriteriaImpl.cs:line
143 at
NHibernate.Impl.MultiCriteriaImpl.List()
in
d:\CSharp\NH\nhibernate\src\NHibernate\Impl\MultiCriteriaImpl.cs:line
91 at
FakturaLight.Repositories.InvoiceRepository.GetSingle(Int32
invoiceId) in
D:\Projekt\faktura_light\src\FakturaLight\Repositories\InvoiceRepository.cs:line
168 at
FakturaLight.WebClient.Controllers.InvoiceController.PrepareEditInvoiceModel(EditInvoiceModel
oldModel, Int32 id) in
D:\Projekt\faktura_light\src\FakturaLight.WebClient\Controllers\InvoiceController.cs:line
116 at
FakturaLight.WebClient.Controllers.InvoiceController.Edit(Int32
id) in
D:\Projekt\faktura_light\src\FakturaLight.WebClient\Controllers\InvoiceController.cs:line
82 at lambda_method(Closure ,
ControllerBase , Object[] ) at
System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase
controller, Object[] parameters) at
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext
controllerContext, IDictionary2
parameters) at
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext
controllerContext, ActionDescriptor
actionDescriptor, IDictionary2
parameters) at
System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClassd.b__a()
at
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter
filter, ActionExecutingContext
preContext, Func1 continuation)preContext, Func1 continuation)1.terminated.

It's by design. Just create another session.
If the Session throws an exception,
the transaction must be rolled back
and the session discarded.
(please remember that your sessions should be opened late and closed early)

Related

Code first custom SQL migration timeout exception

I am trying to create FULL TEXT index using Entity Framework Migration by executing custom Sql.
My migration class looks like this:
public partial class DocumentContentFullTextIndex : DbMigration
{
public override void Up()
{
AlterColumn("dbo.Attachments", "ContentType", c => c.String(maxLength: 260));
Sql("CREATE FULLTEXT CATALOG FullTextIndexes AS DEFAULT;", true);
Sql(#"CREATE FULLTEXT INDEX ON [Attachments](
Content
TYPE COLUMN ContentType
Language 'ENGLISH'
)
KEY INDEX [PK_dbo.Attachments]
ON FullTextIndexes;", true);
}
public override void Down()
{
AlterColumn("dbo.Attachments", "ContentType", c => c.String(maxLength: null));
Sql("DROP FULLTEXT INDEX ON [Attachments]");
Sql("DROP FULLTEXT CATALOG FullTextIndexes");
}
}
When I run it from MSSQL management studio everything is perfect and SQL did exactly what I am expected from it.
But when running from migration project second Sql request fires exception
Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
Full stack trace with -Verbose flag:
Update-Database -ConnectionStringName DatabaseContext -Verbose
Using StartUp project 'Lx2'.
Using NuGet project 'Database.Model'.
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
Target database is: 'Lx2' (DataSource: ., Provider: System.Data.SqlClient, Origin: Explicit).
Applying explicit migrations: [201406050348083_AttachmentsContentFullTextIndex].
Applying explicit migration: 201406050348083_AttachmentsContentFullTextIndex.
ALTER TABLE [dbo].[Attachments] ALTER COLUMN [ContentType] [nvarchar](260) NULL
CREATE FULLTEXT CATALOG FullTextIndexes AS DEFAULT;
CREATE FULLTEXT INDEX ON [Attachments](
Content
TYPE COLUMN ContentType
Language 'ENGLISH'
)
KEY INDEX [PK_dbo.Attachments]
ON FullTextIndexes;
System.Data.SqlClient.SqlException (0x80131904): Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. ---> System.ComponentModel.Win32Exception (0x80004005): The wait operation timed out
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<NonQuery>b__0(DbCommand t, DbCommandInterceptionContext`1 c)
at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.NonQuery(DbCommand command, DbCommandInterceptionContext interceptionContext)
at System.Data.Entity.Internal.InterceptableDbCommand.ExecuteNonQuery()
at System.Data.Entity.Migrations.DbMigrator.ExecuteSql(DbTransaction transaction, MigrationStatement migrationStatement, DbInterceptionContext interceptionContext)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.ExecuteSql(DbTransaction transaction, MigrationStatement migrationStatement, DbInterceptionContext interceptionContext)
at System.Data.Entity.Migrations.DbMigrator.ExecuteStatementsInternal(IEnumerable`1 migrationStatements, DbTransaction transaction, DbInterceptionContext interceptionContext)
at System.Data.Entity.Migrations.DbMigrator.ExecuteStatementsInternal(IEnumerable`1 migrationStatements, DbConnection connection)
at System.Data.Entity.Migrations.DbMigrator.<>c__DisplayClass30.<ExecuteStatements>b__2e()
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.<>c__DisplayClass1.<Execute>b__0()
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(Action operation)
at System.Data.Entity.Migrations.DbMigrator.ExecuteStatements(IEnumerable`1 migrationStatements, DbTransaction existingTransaction)
at System.Data.Entity.Migrations.DbMigrator.ExecuteStatements(IEnumerable`1 migrationStatements)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.ExecuteStatements(IEnumerable`1 migrationStatements)
at System.Data.Entity.Migrations.DbMigrator.ExecuteOperations(String migrationId, XDocument targetModel, IEnumerable`1 operations, IEnumerable`1 systemOperations, Boolean downgrading, Boolean auto)
at System.Data.Entity.Migrations.DbMigrator.ApplyMigration(DbMigration migration, DbMigration lastMigration)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.ApplyMigration(DbMigration migration, DbMigration lastMigration)
at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.DbMigrator.UpdateInternal(String targetMigration)
at System.Data.Entity.Migrations.DbMigrator.<>c__DisplayClassc.<Update>b__b()
at System.Data.Entity.Migrations.DbMigrator.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration)
at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.Run()
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner)
at System.Data.Entity.Migrations.Design.ToolingFacade.Update(String targetMigration, Boolean force)
at System.Data.Entity.Migrations.UpdateDatabaseCommand.<>c__DisplayClass2.<.ctor>b__0()
at System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(Action command)
ClientConnectionId:3d298f0a-e2dc-4976-8587-c69d03b23c6b
Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
I tried to copy all SQL from Verbose output exactly 'as is' and execute it directly in Management Studio and it work exactly as expected with no errors.
Any ideas how this can be fixed?
Strange thing also that if I put ContentType max length changing code
AlterColumn("dbo.Attachments", "ContentType", c => c.String(maxLength: 260));
in separate migration file everything also works fine.
UPDATE:
After shivakumar advice I tried to increase connection timeout (up to 5 minutes) in migration configuration and this increased time before I received "Timeout exception" but problem is still there.
Use Configuration.cs file to set custom time out:
internal sealed class Configuration : DbMigrationsConfiguration<ApplicationDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
ContextKey = "YourDbContext";
// New timeout in seconds
this.CommandTimeout = 60 * 5;
}
}
Your request processing may be taking more time than default command timeout of entity framework(30 sec).
You can increase command timeout if necessary as in thread below.
Entity Framework Timeouts

SQLDataReader Invalid object name

I am trying to authenticate a user through a login form by reading user details from my database UsersDB. On attempting to read, I get an error: Invalid object name: UsersDB
I got no errors when adding a new user to the database so I do not know why I am getting this error. Here is the stack trace I am getting:
[SqlException (0x80131904): Invalid object name 'UsersDB'.]
System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) +388
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) +810
System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) +4403
System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() +82
System.Data.SqlClient.SqlDataReader.get_MetaData() +135
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) +6666037
System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite) +6667856
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite) +577
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) +107
System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) +288
System.Data.SqlClient.SqlCommand.ExecuteReader() +302
AuthWebRole.Account.UserLogin.Buttonlogin_Click(Object sender, EventArgs e) in c:\Users\Tamara\Documents\Visual Studio 2012\Projects\TCWalletAzure\AuthWebRole\Account\UserLogin.aspx.cs:32
System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +155
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3804
Edit:
The query is as follows: (I replaced my username and password in my code)
string strcon = "Server=tcp:qemcclhlar.database.windows.net,1433;Database=UsersDB;User ID=[userid];Password=[mypassword];Trusted_Connection=False;Encrypt=True;Connection Timeout=30";
SqlConnection con = new SqlConnection(strcon);
SqlCommand com = new SqlCommand("CheckUser", con);
com.CommandType = CommandType.StoredProcedure;
SqlParameter user = new SqlParameter("username", UserName.Text);
SqlParameter pword = new SqlParameter("password", Password.Text);
com.Parameters.Add(user);
com.Parameters.Add(pword);
con.Open();
SqlDataReader rd = com.ExecuteReader();
if (rd.HasRows)
{
rd.Read();
LabelInfo.Text = "Login successful.";
}
else
{
LabelInfo.Text = "Invalid username or password.";
}
Database Schema:
Database: UsersDB with table UserTable
Well the important thing here is probably the connection string. Do the following: create an empty text file and rename it "myconnection.udl". Now double click on the file and it will launch an applet. You can configuer the connection to your database and test it. Now open the udl file in notepad, you will see the correct connection string. Copy connections string to your app connection settings. UDL files are generally misunderstood. They are simply a text file that holds the connection settings. They then call the connection dll. If the udl file works then you have a correct connection string 100%
I solved my problem - I entered the wrong table in the procedure query. It had to be as follows:
create PROCEDURE CheckUser
(
#username as varchar(50),
#password as varchar(50)
)
AS
SELECT * FROM UserTable WHERE Username=#username AND Password=#password
I erroneously entered UsersDB instead of UserTable

NHibernate - HQL "join fetch" with SetMaxResults throws error

I'm trying to run the simplest query:
string queryStr = "select b " +
"from Blog b " +
"left outer join fetch b.BlogComments bc";
IList<Blog> blogs = Session.CreateQuery(queryStr)
.SetMaxResults(10)
.List<Blog>();
But it throws the following error:
System.ArgumentNullException: Value cannot be null.
Parameter name: source
However, if I remove the 'fetch' from the HQL it works fine. Also if I leave fetch in but remove SetMaxResults it also works fine. It's something to do with the fetch + SetMaxResults combination.
I'm trying to eager load child collections to optimise the query and prevent SELECT N+1 problems. I'm using NHibernate 3.3.1.4000 with a MySQL database.
My mapping:
public class BlogMap : ClassMapping<Blog>
{
public BlogMap ()
{
// other properties (snip)....
Set(x => x.BlogComments, x =>
{
x.Inverse(true);
x.Cascade(Cascade.All | Cascade.DeleteOrphans);
x.Lazy(CollectionLazy.Extra);
x.Key(k => { k.Column("BlogId"); });
}, x => x.OneToMany());
}
}
public class BlogCommentMap : ClassMapping<BlogComment>
{
public BlogCommentMap ()
{
// other properties (snip)....
ManyToOne(x => x.Blog, x =>
{
x.Column("BlogId");
x.NotNullable(true);
});
}
}
Stacktrace as requested:
[ArgumentNullException: Value cannot be null.
Parameter name: source]
System.Linq.Enumerable.ToList(IEnumerable`1 source) +4206743
NHibernate.Engine.QueryParameters.CreateCopyUsing(RowSelection selection) +178
NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.List(ISessionImplementor session, QueryParameters queryParameters) +210
NHibernate.Engine.Query.HQLQueryPlan.PerformList(QueryParameters queryParameters, ISessionImplementor session, IList results) +369
NHibernate.Impl.SessionImpl.List(String query, QueryParameters queryParameters, IList results) +301
[GenericADOException: Could not execute query[SQL: SQL not available]]
NHibernate.Impl.SessionImpl.List(String query, QueryParameters queryParameters, IList results) +351
NHibernate.Impl.SessionImpl.List(String query, QueryParameters parameters) +282
NHibernate.Impl.QueryImpl.List() +162
WebApp.Repositories.BlogRepository.SearchBlogs(SearchBlogs search) in C:\...path...\BlogRepository.cs:43
WebApp.Controllers.HomepageController.Index(Int32 page) in C:\...path...\Controllers\HomepageController.cs:54
lambda_method(Closure , ControllerBase , Object[] ) +101
System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +17
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +208
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +27
System.Web.Mvc.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12() +55
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +263
System.Web.Mvc.<>c__DisplayClass17.<InvokeActionMethodWithFilters>b__14() +19
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +191
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +343
System.Web.Mvc.Controller.ExecuteCore() +116
System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +97
System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +10
System.Web.Mvc.<>c__DisplayClassb.<BeginProcessRequest>b__5() +37
System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +21
System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +12
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62
System.Web.Mvc.<>c__DisplayClasse.<EndProcessRequest>b__d() +50
System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f) +7
System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action) +22
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +60
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8970061
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +184
What you are experiencing is a bug... But in this case it could be a good sign! ;) Because paging (SetFirstResult(), SetMaxResults()) on a query fetching parent and its collection will be returning unexpected results. Let's say, that
DB tables contain this:
BlogA
BlogCommentA1
BlogCommentA2
BlogCommentA3
BlogB
BlogCommentB1
BlogCommentB2
QueryOver syntax (which is working) doing the same as the above HQL:
var blogs = session.QueryOver<Blog>()
.Fetch(c => c.BlogComment).Eager // collection in one SQL
.Skip(0).Take(2) // paging, but weird...
.List<Blog>();
.Skip(0).Take(2) - first page, a select resulting in this two rows but ONE BlogA:
| BlogA | BlogCommentA1
| BlogA | BlogCommentA2
.Skip(2).Take(2) - next page, weird... again BlogA
| BlogA | BlogCommentA3
| BlogB | BlogCommentB1
And this is most likely not we want.
Suggestion: go for SELECT 1+1
The most reliable in this case is doing the paging only on the parent object (Blog). And then, when we have in NHibernate session all the blogs (.Skip(2).Take(2)) we will only once call select for all their children (BlogComments).
The easiest way is set the batch-size="x", where x is a number close to the usual page size (e.g. 25 or 50).
.BatchSize(25)
NHibernate documentation 19.1.5. Using batch fetching explains details
This looks like a bug either in QueryParameters.CreateCopyUsing(), or something else is not creating the original QueryParameters correctly. Anyway, using SetMaxResults() with collection joins will force the paging to be applied client side, not in the database, which may not be what you want.
You propably want to rewrite that to use a IN on a subquery that yields 10 blog id and have the join fetching in the outer query.

LINQ to NHibernate - .GroupBy().Skip().Take() cause an exception

NHibernate version 3.3.1.4000
Query:
IQueryable<Activity> activities = _repository.GetList<Activity>();
IQueryable<ActivityStatistic> statistics = activities
.GroupBy(activity => activity.ActivityLicense.SerialNumber)
.Select(grouping => new ActivityStatistic
{
ActivityCount = grouping.Count(),
LicenseCode = grouping.Key
})
.OrderBy(stat => stat.LicenseCode);
List<ActivityStatistic> result = statistics
.Skip(request.StartIndex)
.Take(request.Count)
.ToList();
If I comment Skip/Take code, it works properly. How can I make it to work together without calling ToList() after OrderBy using LINQ to NHibernate?
Thanks in advance.
Update:
Exception:
The method or operation is not implemented.
at NHibernate.Linq.GroupBy.AggregatingGroupByRewriter.FlattenSubQuery(SubQueryExpression subQueryExpression, QueryModel queryModel)
at NHibernate.Linq.GroupBy.AggregatingGroupByRewriter.ReWrite(QueryModel queryModel)
at NHibernate.Linq.Visitors.QueryModelVisitor.GenerateHqlQuery(QueryModel queryModel, VisitorParameters parameters, Boolean root)
at NHibernate.Linq.NhLinqExpression.Translate(ISessionFactoryImplementor sessionFactory)
at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(String queryIdentifier, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)
at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters)
at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow)
at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression)
at NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, IQuery& query, NhLinqExpression& nhQuery)
at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression)
at Remotion.Linq.QueryableBase`1.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at MBP.AuthorizationService.Logic.LicenseService.GetActivityStatistic(CommonRequest request, Int32& recordsCount) in D:\Projects\MBP.Launcher\MBP.AuthorizationService.Logic\LicenseService.cs:line 201
Michael Petito answered to the question:
This is a known issue that I just ran into as well:
nhibernate.jira.com/browse/NH-2566 – Michael Petito Aug 22 at 19:56
Waiting for new releases...

LINQ to SQL delete producing "Specified cast is not valid" error

I've got a painfully simple table that is giving me a "Specified cast is not valid" error when I try to delete one or more rows. The table has two columns, an "id" as the primary key (INT), and a "name" (VARCHAR(20)), which maps to a String in the LINQ to SQL dbml file. Both of these statements produce the error:
dc.DeleteOnSubmit(dc.MyTables.Where(Function(x) x.id = 1).SingleOrDefault)
dc.DeleteAllOnSubmit(dc.MyTables)
I iterated through "MyTable" just to make sure there was no weird data, and there are only two rows:
id = 1, name = "first"
id = 2, name = "second"
The exception is happening on SubmitChanges. Here is the stack trace:
[InvalidCastException: Specified cast is not valid.]
System.Data.Linq.SingleKeyManager`2.TryCreateKeyFromValues(Object[] values, V& v) +59
System.Data.Linq.IdentityCache`2.Find(Object[] keyValues) +28
System.Data.Linq.StandardIdentityManager.Find(MetaType type, Object[] keyValues) +23
System.Data.Linq.CommonDataServices.GetCachedObject(MetaType type, Object[] keyValues) +48
System.Data.Linq.ChangeProcessor.GetOtherItem(MetaAssociation assoc, Object instance) +142
System.Data.Linq.ChangeProcessor.BuildEdgeMaps() +233
System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode) +59
System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode) +331
System.Data.Linq.DataContext.SubmitChanges() +19
InpatientCensus.MaintenanceController.DeleteSoleCommunity(Int32 id) in C:\Documents and Settings\gregf\My Documents\Projects\InpatientCensus\InpatientCensus\Controllers\MaintenanceController.vb:14
lambda_method(ExecutionScope , ControllerBase , Object[] ) +128
System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +17
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +178
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +24
System.Web.Mvc.<>c__DisplayClassa.<InvokeActionMethodWithFilters>b__7() +52
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +254
System.Web.Mvc.<>c__DisplayClassc.<InvokeActionMethodWithFilters>b__9() +19
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +192
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +399
System.Web.Mvc.Controller.ExecuteCore() +126
System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +27
System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +7
System.Web.Mvc.MvcHandler.ProcessRequest(HttpContextBase httpContext) +151
System.Web.Mvc.MvcHandler.ProcessRequest(HttpContext httpContext) +57
System.Web.Mvc.MvcHandler.System.Web.IHttpHandler.ProcessRequest(HttpContext httpContext) +7
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +181
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75
Removing the association added to the DBML file allows rows to be deleted. Why would the association be causing the error? The associated columns are both VARCHAR(20) in the database and resolve to Strings in the DBML file.
What could possibly be causing a casting error?
Okay, upon seeing the update, the issue is the association between your two tables. This is a known bug in .NET 3.5 SP1 and will be fixed in .NET 4.0. Try your code on a .NET 4.0 Beta if you can.
We had a similar problem, caused by using non-integer keys. Details and hotfix number are here: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=351358
Try:
dc.MyTables.DeleteOnSubmit(dc.MyTables.SingleOrDefault(x=>x.id==1));
dc.MyTables.DeleteAllOnSubmit(dc.MyTables);