Рекордсет и ошибки в базе MS SQL

Users
Дата: 04.01.2016 05:51:06
Доброго.

Коллеги, написал процедуру на акцессе + сторку на ms sql. Access 2010/MS SQL 2012

Public Function openSingleValue(ByVal QueryText As String, ByVal FieldName As String) As Variant
Dim rslt As Variant
Dim rst As Recordset
    Set rst = OpenRecordset(QueryText)
    If rst.RecordCount > 0 Then
        rslt = rst.Fields(FieldName).Value
    End If
    rst.Close
    openSingleValue = rslt
End Function


Public Function OpenRecordset(QueryText As String) As DAO.Recordset
On Error GoTo err
  'переопределил текст запроса
  
  'создал временный кверидеф
  Dim qdf As QueryDef
  Set qdf = CreateTempQueryDef(QueryText)
  'собственно открыл рекорсет
  Set OpenRecordset = qdf.OpenRecordset(dbOpenForwardOnly, dbReadOnly)
  qdf.Close
  
Exit Function
err:
MsgBox "Error connection SQL server", vbInformation
qdf.Close
  
End Function


подразумевается, что я передам на сервер значение и вернется мне рекордсет, а потом из него одно значение.

CREATE PROC [dbo].[p_myproc_delete](@id INT)
AS 
BEGIN
	SET NOCOUNT ON;
	DECLARE @Row_Count INT; 
	DECLARE @Error_Code INT;
	SET XACT_ABORT OFF; 	
	DELETE 
	FROM   tbl_mytable
	WHERE  id = @id;
	SELECT @Row_Count = @@ROWCOUNT, @Error_Code = @@ERROR
	
	IF (@Error_Code <> 0) OR (@Row_Count <> 1)
	BEGIN
   		IF @Error_Code = 547  -- существует foreight key  
			BEGIN
				RETURN (-400); -- ошибка - есть ссылка 	
			END
		ELSE 
			BEGIN
				RETURN (-300); -- ошибка при удалении
			END
	END;
	ELSE
	BEGIN
		RETURN @id;
	END;
END;


declare @ret int; exec @ret = dbo.p_myproc_delete @id =2; select @ret as ret;

И, соответственно, с сервера я получаю через Return коды возврата. И все было хорошо ровно до того, как попался foreingn key.
Я пытаюсь удалять, обрабатываю ошибку 547 и получаю код возврата -400, мечтая обработать его в акцессе.

Однако вместе с ним выдается и ошибка на сервере, Msg 547, Level 16, State 0, Procedure p_myproc_delete, Line 13
The DELETE statement conflicted with the REFERENCE constraint ссылки на мои таблиц
The statement has been terminated.
Как результат - генерится ошибка в моей функции OpenRecordset.

И вот вопрос - как эту ошибку на сервере корректно обрабатывать и где? Либо переписать код на сервере на try - catch (как?) либо оставить как есть, но изменить код акцесса(как)?

Заранее спасибо вам за ответы.
Rivkin Dmitry
Дата: 04.01.2016 09:08:37
Если мечтаешь обрабатывть ошибки на Аксе, то и обрабатывай на нем:
Как-то так

Public Function MyDelete(Id Integer) As Integer
On Error GoTo Err_MyDelete
    Dim Dim cnt As New ADODB.Connection,  err As ADODB.Error

    Set cnt = CurrentProject.Connection
    cnt.Execute "delete from tbl_mytable where id = " & Id

    MyDelete = -1

Exit_MyDelete:
    Exit Function

Err_MyDelete:
    For each err in cnt.Errors
        MsgBox err.Description
    Next
    MyDelete = cnt.Errorrs(0).Description
    Resume Exit_MyDelete

End Sub


ЗЫ:
Писал по памяти, могут быть неточности. Но идея, надеюсь, понятна
Users
Дата: 07.01.2016 02:59:31
Rivkin Dmitry,

Нет, это не то. По религиозно-политическим соображением я никогда не работаю с sql сервером напрямую, только через сторки. И плюс у меня DAO. И как показали эксперименты, с ним такое не проходит.
Хотя, может, я и не так экспериментировал.
Users
Дата: 07.01.2016 03:40:50
Users,

Сам себе отвечаю, если кто-то будет искать. Для DAO надо вот так коллекцию ошибок обрабатывать:


For Each oErr In DBEngine.Errors

Next
Rivkin Dmitry
Дата: 07.01.2016 09:15:50
Users
Rivkin Dmitry,

Нет, это не то. По религиозно-политическим соображением я никогда не работаю с sql сервером напрямую, только через сторки. И плюс у меня DAO. И как показали эксперименты, с ним такое не проходит.
Хотя, может, я и не так экспериментировал.

Ну, ежели религиозные соображнгия, тогда продолжай мучаться.
Я, как раз, без всякой религии, исходя из логики (как мне кажется), предпочитаю искать наиболее эффетивные решения. С как можно меньшим количеством заморочек.
Users
Дата: 10.01.2016 18:48:22
Rivkin Dmitry,

Вот если ты ищешь наиболее эффективное решение при работе с sql сервером - то забудь вообще про прямую работу с таблицами. Только сторки и ничего большего.

Ну, а если "эффетивные" решения - то можно, да, и права юзерам давать на таблицы и забывать про то, что процедуры прекомпилятся и так далее.
Rivkin Dmitry
Дата: 18.01.2016 16:35:40
Users,

Мне кажется, тобою неправильно понято правило недопускать юзера напрямую в базу данных. На твоем же примере, из того куска кода, который приведен в первом топике: весь смысл заморочки заключается только в том, что есть опасность удаления вторичного ключа. Но это означает, что юзеру такие права даны. Он может это делать! Так почему бы не проверить наличие записей под этим ключем любыми другими доступными способами? И не заморачиваться с такими сложными выворотами? Уж простой селект, без возврата конкретных данных, а только на предмет наличия присутствия (или отсутствия точнее) можно делать любому юзеру. Но даже если и это нельзя, то тебе, как супервайзеру можно? А юзер код твой не увидит.
С другой стороны, хочешь-не хочешь, а права юзеру определять надо. И в пределах своих прав он (юзер) вправе делать то, что ему позволяет делать программист. (Под незримым присутствием оного)
Шыфл
Дата: 18.01.2016 18:27:30
Users, религия, говоришь, не позвляет? А ODBCDirect используешь?
+

Public dbsDirect As DAO.Database
Public wrkODBC As Workspace         ' workspace variable used for ODBCDirect workspace
Public conPubs As Connection        ' connection variable used in ODBCDirest workspace
Public qdfDirect As QueryDef

Public Function CreateRMTQueryDEF(ConnectString As String) As Integer
On Error GoTo err1
Set wrkODBC = CreateWorkspace("", "admin", "", dbUseODBC)
    wrkODBC.DefaultCursorDriver = dbUseODBCCursor
    ' Create connection in DirectODBC workspace
    Set conPubs = wrkODBC.OpenConnection("Connect1", dbDriverNoPrompt, , "ODBC;" & ConnectString)
    Set dbsDirect = conPubs.Database
    dbsDirect.QueryTimeout = 0
    
    ' Create queryDef in DirectODBC workspace
    Set qdfDirect = conPubs.CreateQueryDef("NQD")
    qdfDirect.Prepare = dbQUnprepare

    addErrorMessage qd, "Connected", "0", 0
    CreateRMTQueryDEF = RMT_SUCCESS
    Exit Function
err1:
    CreateRMTQueryDEF = RMT_ERROR
End Function