Transaction in Microsoft Acess, error 3034 - vba

I have an issue with Access 2010.
I use transaction to encapsulate my modification in a form. This transaction is started in the Form_Load() sub.
Private Sub Form_Load()
Debug.Print "Right here"
DAO.DBEngine.Workspaces(0).BeginTrans
Debug.Print "Here too"
...
End Sub
So the transaction is started at the very first line (nothing else is running before, the Debug.Print are just here to show you the code run through the line).
When I click on the button "save" or "rollback", I run some code like this :
Private Sub BtnSauvegarder_Click()
DAO.DBEngine.Workspaces(0).CommitTrans dbForceOSFlush
DoCmd.OpenForm "F_ListeDemande", acNormal, , , acFormEdit, acWindowNormal
DoCmd.Close acForm, Me.name
End Sub
And that's here I got the error 3034, both in save or rollback code (which are similar)
BUT, the weirdest thing is here : when I entered the form, my Listbox are bugy, nothing are inside. If I entered in Design view, do nothing and then entered in the Normal view, everything run right : Listbox have the Recordset they are supposed to have and the transaction work fine.
This is not the first time I use transaction, I used the same way on other forms without any problem.
So what I am doing wrong ?
EDIT :
I made this code to output the current state of DAO.DBEngine, in case it is useful.
Public Sub DebugDBEngine()
Dim ws As Workspace
Dim db As Database
Dim p As Property
For Each ws In DAO.DBEngine.Workspaces
Debug.Print "Workspace : " & ws.name
For Each p In ws.Properties
On Error Resume Next
Debug.Print "| " & p.name & " = " & p.value
Next
For Each db In ws.Databases
Debug.Print "| Database : " & db.name
For Each p In db.Properties
On Error Resume Next
Debug.Print "| | " & p.name & " = " & p.value
Next
Next
Next
End Sub
So I use it just after the beginning of the transaction and the output is this :
Workspace : #Default Workspace#
| Name = #Default Workspace#
| UserName = admin
| IsolateODBCTrans = 0
| Type = 2
| Database : H:\Projet\05\15\10h28 - Suivi commande et fournisseur.accdb
| | Name = H:\Projet\05\15\10h28 - Suivi commande et fournisseur.accdb
| | Connect =
| | Transactions = True
| | Updatable = True
| | CollatingOrder = 1036
| | QueryTimeout = 60
| | Version = 14.0
| | RecordsAffected = 0
| | ReplicaID =
| | DesignMasterID =
| | ANSI Query Mode = 0
| | Themed Form Controls = 1
| | AccessVersion = 09.50
| | NavPane Category = 0
| | UseMDIMode = 0
| | ShowDocumentTabs = True
| | Build = 24
| | HasOfflineLists = 70
| | Picture Property Storage Format = 0
| | CheckTruncatedNumFields = 1
| | ProjVer = 119
| | NavPane Closed = 0
| | NavPane Width = 226
| | NavPane View By = 0
| | NavPane Sort By = 1
| | Show Navigation Pane Search Bar = 0
| | WebDesignMode = 0
| | Theme Resource Name = Thème Office
| | Property Sheet Label Width = 2820
| | StartUpShowDBWindow = True
| | StartUpShowStatusBar = True
| | AllowShortcutMenus = True
| | AllowFullMenus = True
| | AllowBuiltInToolbars = True
| | AllowToolbarChanges = True
| | AllowSpecialKeys = True
| | UseAppIconForFrmRpt = False
| | AllowDatasheetSchema = True
| | DesignWithData = True
| | Show Values Limit = 1000
| | Show Values in Indexed = 1
| | Show Values in Non-Indexed = 1
| | Show Values in Remote = 0
| | Auto Compact = 0
| | Track Name AutoCorrect Info = 0
| Database : H:\Projet\05\15\10h28 - Suivi commande et fournisseur.accdb
| |(same things as above, it is the same database)
So, the same DB is open twice. I verify : where the transactions are correctly runing, only one DB is open.
EDIT2 :
I tested again with this debug to enter in normal view, then design and then normal. The first time, I've got the output just above. The second time, it is the same without the second same database, there is juste one DB.
So now, I'm sure the problem is they are two databases opened. All I have to find is WHY it open twice the same DB.

With hard searching, I probably found the problem.
In Design view, I set to Listboxes some query to fill them. It use one database to do it.
In my VBA code, I use Recordset to fill the Listboxes. And they use another database, even if it is the same.
So my solution is simple : I don't define the rowsource in Design view, so only the VBA will fill the Listboxes.

Related

VBA find a word and add a column

I would like create a macro (VBA) that find a word and in another cell give a word.
Example:
|A | B | macro result|
|--|-----------------------|-------------|
|1 |my cat is on the table | ok |
|2 |Hi | |
|3 |this is my house | ok |
I have try this but it doesn't work. Can you help me?
Sub Macro1()
riga = 1
While (Sheets("Foglio2").Cells(riga, 1) <> "")
If (Sheets("Foglio2").Cells(riga, 2) Like "my") Then
Sheets("Foglio2").Cells(riga, 3) = "ok"
End If
riga = riga + 1
Wend
End Sub
Sub Macro1()
riga = 1
While (Sheets("Foglio2").Cells(riga, 1) <> "")
If Instr(Sheets("Foglio2").Cells(riga, 2), "my") > 0 Then
Sheets("Foglio2").Cells(riga, 3) = "ok"
End If
riga = riga + 1
Wend
End Sub

Datagridview add column data if it contain number

I've a datagridview like this:
------------------------
| S.N |Data1 | Data2|
| 1 | - | 10 |
| 2 | 4 | 2 |
| 3 | 2 | - |
| 4 | 9 | - |
I want result like this:
------------------------
| S.N |Data1 | Data2|
| 1 | - | 10 |
| 2 | 4 | 2 |
| 3 | 2 | - |
| 4 | 9 | - |
| total | 15 | 12 |
-----------------------
I've tried this:
Dim data1 As double = 0
Dim data2 As double = 0
For i As Integer = 0 To DataGridView1.RowCount - 1
data1 += Val(CDbl(DataGridView1.Rows(i).Cells(1).Value))
data2 += Val(CDbl(DataGridView1.Rows(i).Cells(2).Value))
Next
Dim rows As String() = {"Total", data1, data2}
DataGridView1.Rows.Add(rows)
But it has shown an error:
Can I extract number only from datagridview and display sum of them
and add to the last row?
And now I get my answer:
Dim data1 As double = 0
Dim data2 As double = 0
For j As Integer = 0 To DataGridView1.RowCount - 1
If Regex.IsMatch(DataGridView1.Rows(j).Cells(1).Value, "^[0-9 ]+$") Then
data1 += Val(CDbl(DataGridView1.Rows(j).Cells(1).Value))
End If
If Regex.IsMatch(DataGridView1.Rows(j).Cells(2).Value, "^[0-9 ]+$") Then
data2 += Val(CDbl(DataGridView1.Rows(j).Cells(2).Value))
End If
Next
Dim rows As String() = {"Total", data1, data2}
DataGridView1.Rows.Add(rows)
This checks for nulls and ensures the data is numeric.
Dim data1 As double = 0
Dim data2 As double = 0
For i As Integer = 0 To DataGridView1.RowCount - 1
If Not IsDbNull(DataGridView1.Rows(i).Cells(1).Value) AndAlso IsNumeric(DataGridView1.Rows(i).Cells(1).Value) Then data1 += Val(CDbl(DataGridView1.Rows(i).Cells(1).Value))
If Not IsDbNull(DataGridView1.Rows(i).Cells(2).Value) AndAlso IsNumeric(DataGridView1.Rows(i).Cells(1).Value) Then data2 += Val(CDbl(DataGridView1.Rows(i).Cells(2).Value))
Next
Dim rows As String() = {"Total", data1, data2}
DataGridView1.Rows.Add(rows)

VB.NET LINQ To DataTable Select with Where Clause

Here is my data table that I have stored in a data table variable named dt:
Dim dt As New DataTable
+---------+--------+---------------+
| Carrier | AVGTAT | Name |
+---------+--------+---------------+
| ABCD | 2078 | Term Check |
| ABCD | 0 | AdHoc |
| ABCD | 26406 | Cash on Term |
| REWS | 7358 | Failed Bill |
| ZELT | 11585 | BL150 |
I need to get the value of the AVGTAT column using LINQ to DataTable based Where Carrier = "x" and Name = "X"
How can I accomplish that?
Thank you!
Here is the C# version.
var avg = (from t1 in dt.AsEnumerable()
select new
{
Carrier = t1.Field<string>("Carrier"),
Name = t1.Field<string>("Name"),
Avg = t1.Field<int>("AVGTAT")
}).Where(s => s.Carrier == "X" && s.Name == "X")
.Select(v=>v.Avg).FirstOrDefault();
And the VB.NET version
Dim avg = dt.AsEnumerable().[Select](Function(x) New With {
Key .Carrier = x.Field(Of String)("Carrier"),
Key .Name = x.Field(Of String)("Name"),
Key .Avg = x.Field(Of Int32)("Level")
}).Where(Function(s) s.Carrier = "X" AndAlso s.Name = "X")
.[Select](Function(h) h.Avg).FirstOrDefault()

How to transform a repeating list into a list with a count?

I have a list(Of transaction) :
Type | State
----------------
boat | buy
boat | buy
boat | sell
car | sell
car | sell
car | sell
plane| buy
How can I transform it to a list(Of transactionShortened) :
Type | State | Quantity
-----------------------
boat | buy | 2
boat | sell | 1
car | sell | 3
plane| buy| | 1
Elegantly.
Use LINQ and Enumerable.GroupBy:
Dim transactionGroups =
From t In transactions
Group t By Key = New With {
.Type = t.Type,
.State = t.State
} Into Group
Select New With {
.Type = Key.Type,
.State = Key.State,
.Quantity = Group.Count()
}
For Each tGroup In transactionGroups
Dim type = tGroup.Type
Dim state = tGroup.State
Dim quantity = tGroup.Quantity
Next

Summing values based on type then on Month

I have a List<Object> where Object contains Name, Month, Type, Value.
is it possible to sum all the Value based on type, and then based on month?
I am using .NET 3.0 in VB.NET
I was doing withe like 4 For loops, but its taking a while to run.
Is there a quicker way?
For clarification, I have something like this:
Name | Month | Type | Value
-----------------------------
hello | Jan | A | 1
hello | Jan | A | 2
hello | Jan | B | 2
hello | Feb | A | 3
hello1 | Jan | A | 6
hello1 | Jan | A | 2
hello1 | Jan | B | 2
hello1 | Feb | A | 3
I want to produce it into this
Name | Month | Type | Value
---------------------------
hello | Jan | A | 3
hello | Jan | B | 2
hello | Feb | A | 3
hello1 | Jan | A | 8
hello1 | Jan | B | 2
hello1 | Feb | A | 3
If LINQ is not possible:
You could use Dictionarys to hold the month-values and the type-values. So you only need one loop to fill all. Here is an example:
Foo is your object and FooType is your type:
Class Foo
Public Enum FooType As Int32
FirstType = 1
SecondType = 2
ThirdType = 3
FourthType = 4
FifthType = 5
End Enum
Public Property Name As String
Public Property Month As Date
Public Property type As FooType
Public Property value As Double
End Class
load some sample-data:
Dim monthRnd As New Random(Date.Now.Millisecond)
Dim yearRnd As New Random(Date.Now.Millisecond)
Dim valueRnd As New Random(Date.Now.Millisecond)
Dim fooTypeRnd As New Random(Date.Now.Millisecond)
Dim allFoos As New List(Of Foo)
For i As Int32 = 1 To 1000
Dim foo As New Foo
foo.Name = i & ". Foo"
foo.type = CType(fooTypeRnd.Next(1, 5), Foo.FooType)
foo.Month = New Date(2000 + yearRnd.Next(0, 12), monthRnd.Next(1, 12), 1)
foo.value = valueRnd.Next(1, 10000) * valueRnd.NextDouble()
allFoos.Add(foo)
Next
Fill total value, grouped by type and by month:
Dim sumTotal As Double = 0D
Dim monthSums As New Dictionary(Of Date, Double)
Dim typeSums As New Dictionary(Of Foo.FooType, Double)
For Each f As Foo In allFoos
sumTotal += f.value
If typeSums.ContainsKey(f.type) Then
typeSums(f.type) += f.value
Else
typeSums.Add(f.type, f.value)
End If
If monthSums.ContainsKey(f.Month) Then
monthSums(f.Month) += f.value
Else
monthSums.Add(f.Month, f.value)
End If
Next
Now you can access these values easily via Dictionary key.
For example:
Dim feb2010Value As Double = 0d
Dim feb2010 As New Date(2010, 2, 1)
If monthSums.ContainsKey(feb2010) Then
feb2010Value = monthSums(feb2010)
End If
I’m still not sure what you want but your example makes it seem as if you group by name and by month and by type at the same time.
Either way, that’s an aggregation into a group. The following should work.
Dim result = From obj In objects _
Group obj By obj.Name, obj.Month, obj.Type Into _
Value = Sum(obj.Value) _
Select Name, Month, Type, Value
However, you shouldn’t use a List(Of Object) – use the correct object type instead.
(Untested, haven’t got VB handy so the actual syntax can deviate in small ways.)