How do I update a change using SubSonic and MySQL - c#

I was trying to TDD using SubSonic 2.1, MySQL and C# and when I got to testing updating an existing record using the code below,
public void Test2()
{
User.Insert("jmarcus1", "jmarcus1", "jackass", "marcus", 3, false);
User users = new User();
int ulevel = 1;
User.Update(2, "jmarcus1", "jmarcus1", "jackass", "marcus", ulevel, false);
Assert.AreEqual(1, users.Ulevel);
}
with the following
------ Test started: Assembly: SalMan.dll ------
Starting the MbUnit Test Execution
Exploring SalMan, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
MbUnit 2.4.2.130 Addin
Found 3 tests
[success] TestFixture1.Test
[success] TestFixture1.Test1
[failure] TestFixture1.Test2
TestCase 'TestFixture1.Test2'
failed: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE `userid` = 1; SELECT 1 AS id' at line 1
MySql.Data.MySqlClient.MySqlException
Message: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE `userid` = 1; SELECT 1 AS id' at line 1
Source: MySql.Data
StackTrace:
at MySql.Data.MySqlClient.MySqlStream.OpenPacket()
at MySql.Data.MySqlClient.NativeDriver.ReadResult(UInt64& affectedRows, Int64& lastInsertId)
at MySql.Data.MySqlClient.MySqlDataReader.GetResultSet()
at MySql.Data.MySqlClient.MySqlDataReader.NextResult()
at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior)
at MySql.Data.MySqlClient.MySqlCommand.ExecuteScalar()
C:\svn\subsonicproject\trunk\SubSonic\DataProviders\MySqlDataProvider.cs(280,0): at SubSonic.MySqlDataProvider.ExecuteScalar(QueryCommand qry)
C:\svn\subsonicproject\trunk\SubSonic\DataProviders\DataService.cs(533,0): at SubSonic.DataService.ExecuteScalar(QueryCommand cmd)
C:\svn\subsonicproject\trunk\SubSonic\ActiveRecord\ActiveRecord.cs(182,0): at SubSonic.ActiveRecord`1.Save(String userName)
D:\My Documents\Visual Studio 2008\Projects\SalMan\SalMan\Generated\User.cs(352,0): at Salman.User.Update(Int32 varUserid, String varUsername, String varPassword, String varFname, String varLname, Int32 varUlevel, Boolean varStatus)
D:\My Documents\Visual Studio 2008\Projects\SalMan\SalMan\Tests\TestFixture1.cs(40,0): at salman.TestFixture1.Test2()
[reports] generating HTML report
TestResults: file:///C:/Documents%20and%20Settings/*****************/Application%20Data/MbUnit/Reports/SalMan.Tests.html
2 passed, 1 failed, 0 skipped, took 7.66 seconds.
Does anyone have a workaround for this?

It looks to me like your args are out of order. The PK should be the first thing - are you sure they are lining up correctly?
Are you using ActiveRecord? If so - have you tried this:
User u=new User();
u.UserName("jmarcus1");
u.Name="jackass"
u.Ulevel=1;
...
u.Save();
User u=new User("jmarcus1");
u.UILevel=2;
u.Save();

apparently the solution was, following Robs excellent advice above, to
User u = User.FetchByID(2);
u.Ulevel = ulevel;
u.save();
i was not too sure that the snippet above would work for updates until you specify
the record you wish to update.
my question to Rob however is, why does "u.Update(2, "jmarcus",..." give the error
above?

Related

Wrong "Duplicate entry '284093' for key 'PRIMARY'" message

Preamble: This question may be useful to people who get wrong error messages when using MySQL. Proof is given that the error message is wrong.
In a MySQL database (version 5.7.18), MyISAM table "sensorhistory" has a column "id" of type "int(11)" with Extra "auto_increment". Data are inserted from an application written in C#. The INSERT query does NOT write the id column directly, of course. That's what the "auto_increment" is for. The table contains further 30 fields of float and varchar types, resp., plus a DateTime(3). The parameterized query is long.
I receive following error message:
Duplicate entry '284093' for key 'PRIMARY'
at MySql.Data.MySqlClient.MySqlStream.ReadPacket()
at MySql.Data.MySqlClient.NativeDriver.GetResult(Int32& affectedRow, Int64& insertedId)
at MySql.Data.MySqlClient.Driver.NextResult(Int32 statementId, Boolean force)
at MySql.Data.MySqlClient.MySqlDataReader.NextResult()
at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior)
at MySql.Data.MySqlClient.MySqlCommand.ExecuteNonQuery()
at DataStorage.SensorHistoryDatastore.StoreSensorHistory(IReadOnlyList'1 _reports, Boolean _canRetry) in C:\Users\bernhard.hiller\SVN\Product-SW\trunk\C_DataStorage\PhysicalContainers\SensorHistoryDatastore.cs:line 84
Oddly, when I execute SELECT max(id) FROM sensorhistory in MySQL Workbench, I get a maximum value of 284092, i.e. 1 less than the "duplicate entry". That is proof that the error message is wrong.
I'd like to know how such an odd error can occur, and how to fix it.
Addendum:
An "Analyze table" in MySQL Workbench showed that the table is corrupt:
Found key at page 6585344 that points to record outside datafile
It could be repaired with a simple Repair table sensorhistory
I am still interested in how that corruption of the table can have occured.
By the way: a big THANK YOU to all those DOWNVOTERS who seem to be unable to read the text: this is not a f***ing stupid question about a "duplicate key", because I showed proof that the duplicate value does not exist at all!
Addendum 208-09-12:
The error re-occured after just 1 day, same table, same error message (just with a new value).
The Windows Eventlog showed more than 7 crashes between Sep 7 and Sep 11 (id 6008: "The previous system shutdown was unexpected"). The newest entry in the table sensorhistory was shortly before such crash in both cases.
The crashes ended on Sep 11 in the morning. I do not know the reason - other people are working on that test machine too. There were no more database issues then.
I conclude that a sudden Windows crash caused some inconsistency in the database, which then lead to that error message.

Azure Mobile Server SDK: When the IQueryable is evaluated?

I have a backend on MS Azure built on top of Azure Mobile App Service SDK (namespace Microsoft.Azure.Mobile.Server.Tables and so on).
It is running ASP.NET MVC over a SQL Server database, in C#.
I have scaffolded my Controllers and I have the method GetAllTodoItems that returns an IQueryable<TodoItem>.
When exactly is this IQueryable evaluated?
I have set up a performance load test and the average request takes 46 seconds to complete, while my visible code and the SQL query takes maximum 5ms!!
What am I missing?
EDIT ====================
Here is my GetAllTodoItems method, together with dependencies:
protected IQueryable<TModelDTO> GetAllEntities()
{
IQueryable<TModel> allEntitiesQuery = Query();
IQueryable<string> visibleObj = context.VisibleObjs(GetUserID(), AttType);
IQueryable<TModel> finalQuery = from item in allEntitiesQuery
join visib in visibleObj on item.Id equals visib
select item;
return finalQuery.Select(Selector).AsQueryable();
}
IQueryable<string> VisibleObjs(string userID, AttachmentType type)
{
return (from ud in UserDesktops
join a in Attachments on ud.DesktopId equals a.ParentDesktop
where (ud.UserId == userID) && (a.AttachmentType == type))
select a.Id);
}
protected Func<TModel, TModelDTO> Selector { get { return d => ToDTO(d); } }
protected override TModelDTO ToDTO(TModel input)
{
return new TModelDTO(input);
}
public TModelDTO(TModel entity)
{
// all basic properties copied:
Content = entity.Content;
Width = entity.Width;
Color = entity.Color;
HighResImageContent = entity.HighResImageContent;
ImageContent = entity.ImageContent;
MaskPath = entity.MaskPath;
MinHeight = entity.MinHeight;
IsComment = entity.IsComment;
IsInkNote = entity.IsInkNote;
}
In this case it could be executing in several locations. Pull the GetUserID method out and put it in a variable above.
var userId = GetUserID();
IQueryable<string> visibleObj = context.VisibleObjs(userId, AttType);
That may solve your performance problem right there - perhaps it is executing that SQL separately, then joining in memory.
In addition, context.VisibleObjs - is context the same context used by Query()? If it is a different context, this won't use SQL to join. You should be getting the context in the Initialize method of the controller and storing it in a class variable there.
Also, what type is AttachmentType? Is it an enum? Perhaps needs cast to an int explicitly? Need more info there.
When exactly is this IQueryable evaluated?
The point at which we want the SQL to run is when it is iterated. In the code above it actually should not run within this method if written correctly. When it is iterated, all expressions before finalQuery.Select(Selector) should be translated into SQL. The Selector method obviously can't be run on the database, so at that time it requires to run the SQL as the query unwinds itself.
The query will unwind itself during serialization.
What does this mean? Well you've handed back to the API an IQueryable object made up of an Expression Tree. The Table Service framework may add some filters or sorts as requested by the web client (see supported query operators). After doing that the web api framework (which called into your controller) will enumerable the IQueryable triggering execution as it writes out JSON(?).
We need to know what SQL is actually running. That's key to working with Linq to SQL / EF.
When faced with troubleshooting Linq to SQL I often put a logger on the context's database. context.Database.Log = Console.Write is the quick solution I use. With a TableController, you would want context.Database.Log = a => this.Configuration.Services.GetTraceWriter().Info(a); in the Initialize method of your controller - where the context is initialized.
Then simply take a look at the log.
I mocked up tables, schema, etc into a TableController and ran this myself, then went through the output with the Logging hooked up, so lets take a look at what's happening:
iisexpress.exe Information: 0 : Request, Method=GET, Url=http://localhost:51543/tables/TodoItem?ZUMO-API-VERSION=2.0.0, Message='http://localhost:51543/tables/TodoItem?ZUMO-API-VERSION=2.0.0'
iisexpress.exe Information: 0 : Message='TodoItem', Operation=DefaultHttpControllerSelector.SelectController
iisexpress.exe Information: 0 : Message='maqsService.Controllers.TodoItemController', Operation=DefaultHttpControllerActivator.Create
iisexpress.exe Information: 0 : Message='maqsService.Controllers.TodoItemController', Operation=HttpControllerDescriptor.CreateController
iisexpress.exe Information: 0 : Message='Selected action 'GetAllTodoItems()'', Operation=ApiControllerActionSelector.SelectAction
iisexpress.exe Information: 0 : Operation=HttpActionBinding.ExecuteBindingAsync
iisexpress.exe Information: 0 : Operation=TableQueryFilter.OnActionExecutingAsync
iisexpress.exe Information: 0 : Operation=EnableQueryAttribute.OnActionExecutingAsync
iisexpress.exe Information: 0 : Operation=TableControllerConfigAttribute.OnActionExecutingAsync
'iisexpress.exe' (CLR v4.0.30319: /LM/W3SVC/2/ROOT-1-131799606929250512): Loaded 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Numerics\v4.0_4.0.0.0__b77a5c561934e089\System.Numerics.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'iisexpress.exe' (CLR v4.0.30319: /LM/W3SVC/2/ROOT-1-131799606929250512): Loaded 'C:\WINDOWS\Microsoft.Net\assembly\GAC_32\System.Data.OracleClient\v4.0_4.0.0.0__b77a5c561934e089\System.Data.OracleClient.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
Next is the line in the log indicating that it got back the IQueryable:
iisexpress.exe Information: 0 : Message='Action returned 'System.Linq.Enumerable+WhereSelectEnumerableIterator`2[maqsService.DataObjects.TodoItem,maqsService.Controllers.TodoItemDTO]'', Operation=ReflectedHttpActionDescriptor.ExecuteAsync
Note, no SQL has been executed. It now identifies that it wants to serialize that in Json:
iisexpress.exe Information: 0 : Message='Will use same 'JsonMediaTypeFormatter' formatter', Operation=JsonMediaTypeFormatter.GetPerRequestFormatterInstance
iisexpress.exe Information: 0 : Message='Selected formatter='JsonMediaTypeFormatter', content-type='application/json; charset=utf-8'', Operation=DefaultContentNegotiator.Negotiate
iisexpress.exe Information: 0 : Operation=ApiControllerActionInvoker.InvokeActionAsync, Status=200 (OK)
iisexpress.exe Information: 0 : Operation=TableControllerConfigAttribute.OnActionExecutedAsync, Status=200 (OK)
Now the JsonSerializer is going to serialize the IQueryable, and to do so it needs to enumerate it.
iisexpress.exe Information: 0 : Message='Opened connection at 8/28/2018 4:11:48 PM -04:00
'
'iisexpress.exe' (CLR v4.0.30319: /LM/W3SVC/2/ROOT-1-131799606929250512): Loaded 'EntityFrameworkDynamicProxies-maqsService'.
iisexpress.exe Information: 0 : Message='SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Text] AS [Text],
[Extent1].[Complete] AS [Complete],
[Extent1].[AttachmentId] AS [AttachmentId],
[Extent1].[Version] AS [Version],
[Extent1].[CreatedAt] AS [CreatedAt],
[Extent1].[UpdatedAt] AS [UpdatedAt],
[Extent1].[Deleted] AS [Deleted]
FROM [dbo].[TodoItems] AS [Extent1]
INNER JOIN (SELECT [Extent2].[UserId] AS [UserId], [Extent3].[Id] AS [Id1], [Extent3].[AttachmentType] AS [AttachmentType]
FROM [dbo].[UserDesktops] AS [Extent2]
INNER JOIN [dbo].[Attachments] AS [Extent3] ON [Extent2].[DesktopId] = [Extent3].[ParentDesktop] ) AS [Join1] ON [Extent1].[Id] = [Join1].[Id1]
WHERE (([Join1].[UserId] = #p__linq__0) OR (([Join1].[UserId] IS NULL) AND (#p__linq__0 IS NULL))) AND ([Join1].[AttachmentType] = #p__linq__1)'
iisexpress.exe Information: 0 : Message='
'
iisexpress.exe Information: 0 : Message='-- p__linq__0: 'dana' (Type = String, Size = 4000)
'
iisexpress.exe Information: 0 : Message='-- p__linq__1: '1' (Type = Int32, IsNullable = false)
'
iisexpress.exe Information: 0 : Message='-- Executing at 8/28/2018 4:11:48 PM -04:00
'
iisexpress.exe Information: 0 : Message='-- Completed in 7 ms with result: SqlDataReader
'
iisexpress.exe Information: 0 : Message='
'
iisexpress.exe Information: 0 : Message='Closed connection at 8/28/2018 4:11:48 PM -04:00
'
SQL complete.
iisexpress.exe Information: 0 : Operation=EnableQueryAttribute.OnActionExecutedAsync, Status=200 (OK)
iisexpress.exe Information: 0 : Operation=TableQueryFilter.OnActionExecutedAsync, Status=200 (OK)
iisexpress.exe Information: 0 : Operation=TodoItemController.ExecuteAsync, Status=200 (OK)
iisexpress.exe Information: 0 : Response, Status=200 (OK), Method=GET, Url=http://localhost:51543/tables/TodoItem?ZUMO-API-VERSION=2.0.0, Message='Content-type='application/json; charset=utf-8', content-length=unknown'
iisexpress.exe Information: 0 : Operation=JsonMediaTypeFormatter.WriteToStreamAsync
iisexpress.exe Information: 0 : Operation=TodoItemController.Dispose
I'm not sure what the performance problems are. While my table has no data I see that it is properly rolling everything up into one SQL. Something that could be different? The type for AttachmentType. I used an int.
What else?
If you want to own the stack and truly understand what's going on under the sheets, There is a series of OData framework filters put on these that are up the call stack also.
This is the stack during the call to the TModelDTO (TodoItemDTO in my example) constructor, which is called during iteration over the SQL result. Note that the stack doesn't have our controller method in in. We've long since handed back the IQueryable. This is back in the framework code where it's actually using that IQueryable, which I'm intercepting because our Select method calls into the DTO to transform it.
maqsService.dll!maqsService.Controllers.TodoItemDTO.TodoItemDTO(maqsService.DataObjects.TodoItem entity) Line 89 C#
maqsService.dll!maqsService.Controllers.TodoItemController.ToDTO(maqsService.DataObjects.TodoItem input) Line 55 C#
maqsService.dll!maqsService.Controllers.TodoItemController.get_Selector.AnonymousMethod__6_0(maqsService.DataObjects.TodoItem d) Line 51 C#
> System.Core.dll!System.Linq.Enumerable.WhereSelectEnumerableIterator<maqsService.DataObjects.TodoItem, maqsService.Controllers.TodoItemDTO>.MoveNext() Unknown
System.Core.dll!System.Linq.Buffer<maqsService.Controllers.TodoItemDTO>.Buffer(System.Collections.Generic.IEnumerable<maqsService.Controllers.TodoItemDTO> source) Unknown
System.Core.dll!System.Linq.OrderedEnumerable<maqsService.Controllers.TodoItemDTO>.GetEnumerator() Unknown
System.Core.dll!System.Linq.Enumerable.TakeIterator<maqsService.Controllers.TodoItemDTO>(System.Collections.Generic.IEnumerable<maqsService.Controllers.TodoItemDTO> source, int count) Unknown
mscorlib.dll!System.Collections.Generic.List<maqsService.Controllers.TodoItemDTO>.List(System.Collections.Generic.IEnumerable<maqsService.Controllers.TodoItemDTO> collection) Line 99 C#
It appears that here, OData evaluating the $top query parameter for a page number does actually then put the results into a list.
System.Web.Http.OData.dll!System.Web.Http.OData.Query.TruncatedCollection<maqsService.Controllers.TodoItemDTO>.TruncatedCollection(System.Linq.IQueryable<maqsService.Controllers.TodoItemDTO> source, int pageSize) Unknown
System.Web.Http.OData.dll!System.Web.Http.OData.Query.ODataQueryOptions.LimitResults<maqsService.Controllers.TodoItemDTO>(System.Linq.IQueryable<maqsService.Controllers.TodoItemDTO> queryable, int limit, out bool resultsLimited) Unknown
I believe the native transition here is SQL related. I can't find exactly whats up in the decompiled source though.
[Native to Managed Transition]
[Managed to Native Transition]
System.Web.Http.OData.dll!System.Web.Http.OData.Query.ODataQueryOptions.LimitResults(System.Linq.IQueryable queryable, int limit, out bool resultsLimited) Unknown
System.Web.Http.OData.dll!System.Web.Http.OData.Query.ODataQueryOptions.ApplyTo(System.Linq.IQueryable query, System.Web.Http.OData.Query.ODataQuerySettings querySettings) Unknown
System.Web.Http.OData.dll!System.Web.Http.OData.EnableQueryAttribute.ApplyQuery(System.Linq.IQueryable queryable, System.Web.Http.OData.Query.ODataQueryOptions queryOptions) Unknown
System.Web.Http.OData.dll!System.Web.Http.OData.EnableQueryAttribute.ExecuteQuery(object response, System.Net.Http.HttpRequestMessage request, System.Web.Http.Controllers.HttpActionDescriptor actionDescriptor) Unknown
System.Web.Http.OData.dll!System.Web.Http.OData.EnableQueryAttribute.OnActionExecuted(System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext) Unknown
To dig even deeper, how does the framework know what to do with the IQueryable anyhow?! Well when it iterates it, the IQueryable uses its IQueryProvider to parse out the contained Expression (note this is not compiled code, this is a tree of method calls and operators which you added using your joins and where clauses). It transforms that tree into SQL (in this case) as best it can. When it hits something it can't translate it throws up an error or finds a way to work around.
Gaining a deep understanding of IQueryProvider is a fairly complex computer science task. You could get started here with a walkthrough of creating a Query Provider. Once upon a time I wrote a query provider to transform Linq expressions into Ektron CMS API calls, and you could take a look at that here. I wrote a pretty good summary with links to key areas.
I hope that helped. Not sure what else I could have gone deeper into, and thank you for teaching me something new today. I had no clue what this mobile table API is (still not clear on the point of it)
Linq is lazy, which means that it is executed actually when you try to access the enumeration like in a foreach loop or some extension methods like .ToList() or .ToArray(). When you define the linq query in your method, than it is simple a "preparation" what should be done, when accessing the result. The preparation of the query takes just a little moment in contrast of the execution. This is the reason why you see that your own code runs in a few milliseconds. It's only a preparation. Finally when you access the result, the query is executed actually, e.g. when asp.net serializes your data to build the response of a request.
In your case you try to build a case insensitive filter
where (ud.UserId.Equals(userID, StringComparison.InvariantCultureIgnoreCase)
in VisibleObjs() method. The Equals(userID, StringComparison.InvariantCultureIgnoreCase) call seems to enforce EF to query/return all data from the table before processing the filter when executed. The evaluation of your filter is executed on the client side instead of using a case insensitive search on the sqlserver. One possible solution can be to mark your sqlserver column UserDesktops.UserId in the database with a collation "SQL_Latin1_General_CP1_CI_AS" where CI means CaseInsensitive. After that you should replace your filter by
where (ud.UserId == userID)
or something similar without using any .Net methods to allow EF to translate your linq filter to a plain sql comparison. In this case the case insensitive filter is processed by sqlserver directly without requesting the full table from sqlserver and filtering on client side.
For the action which returns IQueryable data in ApiController, the Web API will do ToList operation and then serializes the list value, finally writes the serialized the list into the response body, and the response status code is 200 (OK).
Only when we execute the "ToList" method of IQueryable, the data in database is actually taken and the "Excute" method in "IQueryProvider" is executed. (parses the expression, and then executes to get the result).
As you said that it takes 46 seconds to complete, i guess that you do some time-consuming operation with IQueryable, for example: Taking IEnumerable first and then filter the data will cause performance problems.
You can provide us with more detailed code for further research.
Hope this was helpful.

Simple bulk delete using EntityFramework.Extended throws syntax error

I am using Entity Framework 6.1.1 with MySQL 5.6.24 and I want to bulk delete a large set of records.
I am using EntityFramework.Extended to improve performance.
However my first, very simple update query already fails:
DbContext.Tickets.Where(t => t.EventID == targetEvent.EventID).Delete();
This throws an AggregateException in mscolib, the inner Exception is a MySQLException:
[MySqlException (0x80004005): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '[youreal_TicketPlatform].[Tickets]
FROM [youreal_TicketPlatform].[Tickets] AS j' at line 1]
MySql.Data.MySqlClient.MySqlStream.ReadPacket() +501
MySql.Data.MySqlClient.NativeDriver.GetResult(Int32& affectedRow, Int64& insertedId) +444
MySql.Data.MySqlClient.Driver.NextResult(Int32 statementId, Boolean force) +136
MySql.Data.MySqlClient.MySqlDataReader.NextResult() +1254
MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior) +2626
MySql.Data.MySqlClient.MySqlCommand.ExecuteNonQuery() +137
EntityFramework.Batch.<InternalDelete>d__0`1.MoveNext() +1350
Has anyone experienced this same error? What is the easiest way to see the actual query being performed? Adding a listener on DbContext.Database.Log doesn't show the query.
Basically I want to bulk remove large sets of data without having to retrieve them first.
I came across this issue and had found the solution. Just change the default BatchRunner of the Locator from SqlServerBatchRunner to MySqlBatchRunner and it will work with MySQL.
EntityFramework.Locator.Current.Register<EntityFramework.Batch.IBatchRunner>(
() => new EntityFramework.Batch.MySqlBatchRunner());
The related code in repository:
https://github.com/loresoft/EntityFramework.Extended/blob/master/Source/EntityFramework.Extended/Locator.cs
The related issue:
https://github.com/loresoft/EntityFramework.Extended/issues/163
I'm sure it's because you are using mysql. None of the Bulk tools for EF I know works with mysql. And if you look in source/Database for Extended it only contains SqlServer and SqlCompact.
You can write the Sql yourself and execute that through Entityframework.

mysql Error:13 MyISAM table file not found

I have a set of files (around 20MB each) that needs to be inserted into a table in mysql. The insert is done in a loop for all files (single threaded). This works usually fine, but from time to time I am getting the following exception: File '.table.MYD' not found (Errcode: 13) for one file in the middle of the set (the first 50 ran ok, next 2-3 will fail and then the following will run fine again). If I just re-run the queries for the failed files in mysql workbench (or re-run the failed ones), they are working fine. The table is just created, with no indexes - so problems like 'index failed', table fragmentation or any other problems should not be there.
Below is the complete stacktrace:
File '.dbtable.MYD' not found (Errcode: 13)
----------------------------------
at MySql.Data.MySqlClient.MySqlStream.ReadPacket()
at MySql.Data.MySqlClient.NativeDriver.GetResult(Int32& affectedRow, Int32& insertedId)
at MySql.Data.MySqlClient.Driver.NextResult(Int32 statementId, Boolean force)
at MySql.Data.MySqlClient.MySqlDataReader.NextResult()
at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior)
at MySql.Data.MySqlClient.MySqlCommand.ExecuteNonQuery()
at Utils.SqlUtils.ExecMysql(String sql, String connection)
at Utils.MySqlExecQueue.DoExec(Object data)
----------------------------------
MySql.Data
where:
+ ExecMysql - looks like
using (MySqlConnection cnn = new MySqlConnection(connection))
{
cnn.Open();
using (MySqlCommand cmd = new MySqlCommand(sql, cnn))
{
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
}
+DoExec is a method that pics the files from a queue, creates the sql statement and calls ExecMysql above.
+the inserting code and mysql are on the same machine (Windows 2008, x64);
+there are no antiviruses or any other tool running on that machine that may lock the table file (as found on some blogs);
+the c# (.net 4) code is using mysql connector 6.5.4, the mysql version is 5.5;
I have implemented a dummy workaround like 'try-to-insert-while-13error-exception-is-thrown' but I have a strong feeling that this is not the correct solution.
Any ideea what is going on and how to fix this issue once and for all?
UPDATE - Clearly, the 'try-to-insert-while-13error-exception-is-thrown' fix is not a good ideea: I just got the same exception while running a SELECT on the table right after succesfully inserted data.
UPDATE 2 - checked the logs and I have noticed another wierd exception: Error on rename of '.\db\table.MYD' to '.\db\#sql2-4e4-1677.MYD' (Errcode: 17) ... things are getting better ...
do you have any anti-virus? If so make sure the mysql directory and its temp folder are excluded from AV and try again.

Error handling in DTS Package execution using .NET

I am executing a SQL Server 2000 DTS package using C# by following the code from this article http://support.microsoft.com/kb/319985. once the package is executed I am looping through each step to find out if any step has failed and get info about error if it has failed. I also use this information to find out if the package has succeeded or not (package failed if anyone step has failed).
the issue I am facing here is that sometimes the package fails (jumps to catch block) with a generic error message that "Execution was canceled by user" and doesn't give any more information than that. If I run the package manually using the DTSRUNUI then I found that the package was expecting a text file as an input and the file didn't exist in the specified location. in that case the error message from .NET code should say that clearly. do I need to make any changes to the code from the article, to get more details about the errors. I added the following extra to get error information, but didn't help much. there are two properties called "FailonError" on package and "ExecuteInMainThread" on step objects. I tried setting them as well, but that also didn't help. not sure if they are required.
bool success = true;
if (package != null)
{
foreach (Step step in package.Steps)
{
if (step.ExecutionStatus == DTSStepExecStatus.DTSStepExecStat_Completed
&& step.ExecutionResult == DTSStepExecResult.DTSStepExecResult_Failure)
{
int errorCode, helpContext;
string errorSource, errorDescription, helpFile, iDofInterfaceWithError;
step.GetExecutionErrorInfo(out errorCode, out errorSource, out errorDescription, out helpFile,
out helpContext, out iDofInterfaceWithError);
LogToTextFile(
string.Format(
"step name: {0} error Code : {1}, error Source : {2}, error Description: {3}", step.Name,
errorCode, errorSource, errorDescription));
success = false;
}
}
}
I am using DTSRun.EXE to execute the DTS package (by launching the process from C#) and redirecting its console output to the file and that output is normally sufficient in case of any errors.

Categories