Multiple rollbacks to diferents methods Entity Framework VB.NET - asp.net

I have this case: I'm using Entity Framework 6 and I'm trying to insert registries into multiple tables like this:
public function method1(model as modelType) as result
dim answer = new result(false)
dim ent = new entitiType
Using context as database1Context
Using dbContextTransaction = context.Database.BeginTransaction()
Try
model.property3 = method2(model.property2, model.property2)
model.property4 = method3()
context.ent.add(model)
contex.savechanges()
answer.ok = true
DbContextTransaction.Commit()
catch ex as Exception
answer.detail = ex.innerException.Message
DbContextTransaction.Rollback()
End Try
End Using
End Using
Return Answer
End Function
This is my method2:
public function method2(idcta as integer) as integer
dim folio As integer
using context as new database1Context
dim values = (From a In context.cuentas
Where a.idcta = idcta Select a).SingleOrDefault()
values.property = values.property +1
context.savechanges()
End Function
(The method3 is identical to method2)
My question is, how can I roll back every insert or update, when any one of these methods fails?
Thank you for your help.

Related

Access VB property based on name as string - Fastest Option

I'm developing an ASP.NET MVC web app in VB and I am required to output a set of data to a table format, and to allow the user to configure the order and presence of columns from an available set. The data set is stored as a list of the object type representing the row model.
Currently, I implement this using CallByName. Iterating over an ordered list of property names and outputting the value from the instance of the row model. However, based on testing this seems to be a major bottleneck in the process.
I've seen a recommendation to store delegates to get the property, against the string representation of the property's name. So, I can presumably do something like this:
Public Delegate Function GetColumn(ByRef RowObj As RowModel) As String
Dim GetPropOne As GetColumn = Function(ByRef RowObj As RowModel) RowObj.Prop1.ToString()
Dim accessors As New Hashtable()
accessors.Add("Prop1", GetPropOne)
Then, loop through and do something like this:
Dim acc As GetColumn = accessors(ColumnName)
Dim val As String = acc.Invoke(currentRow)
It looks faster, but it also looks like more maintenance. If this is indeed faster, is there a way I can dynamically build something like this? I'm thinking:
Public Delegate Function GetObjectProperty(Instance As Object) As Object
For Each prop In GetType(RowModel).GetProperties()
Dim acc As GetObjectProperty = AddressOf prop.GetValue
columns.Add(prop.Name, acc)
Next
Dim getColVal As GetObjectProperty = columns(ColumnName)
Dim val As String = getColVal.Invoke(currentRow).ToString()
Open to suggestions for different approaches.
I do a similar thing to turn a SOAP response into a Data Table
Public Function ObjectToDataSource(objName) As DataSet
Dim CollName = ""
Dim ds As New DataSet()
For Each m As System.Reflection.PropertyInfo In objName.GetType().GetProperties()
If m.CanRead Then
If InStr(m.PropertyType.ToString, "[]") <> 0 Then
CollName = m.Name
Exit For
End If
End If
Next
Dim CollObj
CollObj = CallByName(objName, CollName, CallType.Get)
If CollObj.length = 0 Then
Call EndTask("No Supply Chains to display", "Royal Mail failed to return Supply Chain information for these credentials", 3)
Else
Dim dt_NewTable As New DataTable(CollName)
ds.Tables.Add(dt_NewTable)
Dim ColumnCount = 0
For Each p As System.Reflection.PropertyInfo In CollObj(0).GetType().GetProperties()
If p.CanRead Then
If p.Name <> "ExtensionData" Then
dt_NewTable.Columns.Add(p.Name, p.PropertyType)
ColumnCount = ColumnCount + 1
End If
End If
Next
Dim rowcount = CollObj.Length - 1
For r = 0 To rowcount
Dim rowdata(ColumnCount - 1) As Object
For c = 0 To ColumnCount - 1
rowdata(c) = CallByName(CollObj(r), dt_NewTable.Columns.Item(c).ToString, CallType.Get)
Next
dt_NewTable.Rows.Add(rowdata)
rowdata = Nothing
Next
End If
Return ds
End Function
This is specific to my needs in terms of getting CollName and not requiring ExtensionData
If ColumnName is the same name as one of the RowModel's properties I don't see why you need the long workaround with delegates...
An extension method which gets only the property you want right now is both faster and consumes less memory.
Imports System.Runtime.CompilerServices
Public Module Extensions
<Extension()> _
Public Function GetProperty(ByVal Instance As Object, ByVal PropertyName As String, Optional ByVal Arguments As Object() = Nothing) As Object
Return Instance.GetType().GetProperty(PropertyName).GetValue(Instance, Arguments)
End Function
End Module
Example usage:
currentRow.GetProperty("Prop1")
'or:
currentRow.GetProperty(ColumnName)

Why can't I consume my webservice more than once?

When I consuming a webservice (asmx) the first time and return a DataTable to my aspx project, everything is ok. However, if I consume the webservice again on that same aspx the previous DataTable object is completely empty. Why is that?
This is my webservice method:
<WebMethod()> _
public Function QueryGeneralText() As DataTable
ds.Reset()
com.Parameters.Clear()
com.CommandText = queryString
com.CommandType = select booksID from Books"
com.Connection = con
conectarBD()
da = New SqlDataAdapter(com)
da.Fill(ds)
con.Close()
Return ds.Tables(0)
End Function
On the aspx.vb section:
Public Sub CreateDatatable()
Dim example1 As DataTable = ws.QueryGeneralText() ' RETURNS DATA
Dim example2 As DataTable = ws.QueryGeneralText() ' RETURNS DATA, BUT EXAMPLE ITS EMPTY
End Sub
It looks like you are using a global ds object - so you function is working on the same resultset.
First time you execute the function it works, nobody else has any results in ds, but next time you already have results there but now your reset drops the results.
If this is true, you might fix it by creating the ds inside the function instead if possible.

Translate powershell query to vb.net query

What is the vb.net equivalent for these four lines in powershell. It's related to my other question regarding generating a dropdownlist on a webpage. From a powershell perspective I know this query generates a list. Thanks.
$dom = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
$domnames = $dom.Domains
$fqdns = $domnames | Select -exp Name
$fqdns = $fqdns
Below example is in C#. Hopefully, you can easily get it converted in VB.NET.
Add a reference of System.DirectoryServices assembly and then use below code sample
using System.DirectoryServices.ActiveDirectory;
class Program
{
static void Main(string[] args)
{
Forest fc = Forest.GetCurrentForest();
DomainCollection dc = fc.Domains;
foreach (var item in dc)
{
Console.WriteLine(item.ToString());
}
}
}
You can do that in single line using LINQ:
Dim fqdns As String() = System.DirectoryServices.ActiveDirectory.Forest.GetCurrentForest().Domains.[Select](Function(x) x.Name).ToArray()
This assigns a value to an array of string named fqdns.
Maybe this can make your code work:
Dim Domains As DomainCollection = Forest.GetCurrentForest.Domains
For Each obj In Domains
ComboBox1.Items.Add(obj.Name)
Next obj
This worked to populate dropdownbox1 in the default.aspx page
Public Function EnumerateDomains() As ArrayList
Dim alDomains As New ArrayList()
Dim currentForrest As Forest = Forest.GetCurrentForest()
Dim myDomains As DomainCollection = currentForrest.Domains
For Each objDomain As Domain In myDomains
alDomains.Add(objDomain.Name)
Next
Return alDomains
End Function
Public Function EnumerateDomains() As ArrayList
Dim alDomains As New ArrayList()
Dim currentForrest As Forest = Forest.GetCurrentForest()
Dim myDomains As DomainCollection = currentForrest.Domains
For Each objDomain As Domain In myDomains
alDomains.Add(objDomain.Name)
Next
Return alDomains
End Function

vb.net Web Server linq to sql returns

My last question was not clear. Im trying to make a web service in VB.net is their a way that i can return the results that i get from LINQ. ie "return objreturnLINQResults"
I have tryed to set my Public Function GetAlarmsByGUIS(ByVal DeptGUID As String, ByVal IdNumber As String) As Linq.DataContext . i just keep getting errors. help please.
Public Function GetAlarmsByGUIS(ByVal DeptGUID As String, ByVal IdNumber As String) As Linq.DataContext
Dim lqAlarms As New linqAlarmDumpDataContext
Dim Temp As String = ""
Dim n As Integer = 0
Dim GetAlrms = From r In lqAlarms.AlarmDrops _
Where r.DeptGUID = DeptGUID And Not r.AlarmsHandled.Contains(IdNumber) _
Order By r.TimeDate Descending _
Select r
Return GetAlrms
End Function
1) You can't create web service's method which returns DataContext object.Return values and input parameters of Web service methods must be serializable through the XmlSerializer class. DataContext is not serializable
2) The simplest way to avoid errors it is return an array of serializable objects. Like this Return GetAlrms.ToArray();

How to add Transactions with a DataSet created using the Add Connection Wizard?

I have a DataSet that I have added to my project where I can Insert and Add records using the Add Query function in Visual Studio 2010, however I want to add transactions to this, I have found a few examples but cannot seem to find one that works with these.
I know I need to use the SQLClient.SQLTransaction Class somehow. I used the Add New Data Source Wizard and added the Tables/View/Functions I need, I just need an example using this process such as How to get the DataConnection my DataSet has used. Assuming all options have been set in the wizard and I am only using the pre-defined adapters and options asked for in this wizard, how to I add the Transaction logic to my Database.
For example I have a DataSet called ProductDataSet with the XSD created for this, I have then added my Stock table as a Datasource and Added an AddStock method with a wizard, this also if a new item calls an AddItem method, if either of these fails I want to rollback the AddItem and AddStock in this case.
In this example, I have a dataset called "dsMain" and a few direct queries in a "QueriesTableAdapter". I extend the partial class for the TableAdapter with a function that will create a transaction based on the first (0) connection and then apply it to every connection in the table adapter.
Namespace dsMainTableAdapters
Partial Public Class QueriesTableAdapter
Public Function CreateTransaction() As Data.IDbTransaction
Dim oConnection = Me.CommandCollection(0).Connection
oConnection.Open()
Dim oTrans = oConnection.BeginTransaction()
For Each cmd In Me.CommandCollection
cmd.Connection = oConnection
cmd.Transaction = oTrans
Next
Return oTrans
End Function
End Class
End Namespace
You begin the transaction by calling the new function
Dim qa As New dsMainTableAdapters.QueriesTableAdapter
Dim oTrans = qa.CreateTransaction()
Then you can call TableAdapter queries within your transaction
qa.Query1
qa.Query2
When you are done with your queries you commit the transaction
oTrans.Commit()
You can do the same thing for any TableAdapter that was created for your datasets.
If you have multiple TableAdapters that need to use the same transaction, then in addition to a "CreateTransaction" you should make a "SetTransaction" and have the Transaction be a parameter.
first of all thanks for your answer carter, it helped me very much!
but iam not able to handle the part with the parameters
You can do the same thing for any TableAdapter that was created for your datasets. If you have multiple TableAdapters that need to use the same transaction, then in addition to a "CreateTransaction" you should make a "SetTransaction" and have the Transaction be a parameter.
so iam able to handle 1 transactions with 1 tableadapter, but not 1 transaction with 2 tableadapters:
iam doing this for a school project, and i really need your help!!
here is the code to add a new material and a historical price to it(a changing price, like by fuel; iam saving it in an related table to material in the database):
Namespace DataSetTableAdapters
Partial Public Class MaterialPriceTableAdapter
Public Function SetTransaction() As Data.IDbTransaction
Dim oConnection = Me.CommandCollection(0).Connection
oConnection.Open()
Dim oTrans = oConnection.BeginTransaction()
For Each cmd In Me.CommandCollection
cmd.Connection = oConnection
cmd.Transaction = oTrans
Next
Return oTrans
End Function
End Class
Partial Public Class MaterialTableAdapter
Public Function CreateTransaction(ByVal MaterialPrice As System.Data.Odbc.OdbcTransaction) As Data.IDbTransaction
Dim oConnection = Me.CommandCollection(0).Connection
oConnection.Open()
Dim oTrans = oConnection.BeginTransaction()
For Each cmd In Me.CommandCollection
cmd.Connection = oConnection
cmd.Transaction = oTrans
Next
Return oTrans
End Function
End Namspace
`
and now the code in the form the form:
Public Class AddMaterial
Dim material As New DataSetBATableAdapters.MaterialTableAdapter
Dim materialprice As New DataSetBATableAdapters.MaterialPriceTableAdapter
Dim oTrans = material.CreateTransaction(materialprice.SetTransaction())
Private Sub Save_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Save.Click
Try
material.InsertQuery(NameTextBox.Text, UnitComboBox.SelectedValue)
materialprice.InsertQuery(Date_BeginDateTimePicker.Value, PriceTextBox.Text, Date_EndDateTimePicker.Value, Me.LkwTableAdapter.ScalarQuery())
oTrans.Commit()
Catch ex As Exception
oTrans.Rollback()
MsgBox("Error by Insert")
End Try
Me.Close
End Sub
End Class
if i save a new record the materialprice.insertquery isnt commited by otrans.commit. what am i doing wrong? if you have an idea what it is, please tell me
thanks,
Xeras
This is untested, but this is how I imaging the CreateTransaction/SetTransaction combo should be written (with your OdbcTransaction object).
Public Function CreateTransaction() As System.Data.Odbc.OdbcTransaction
Dim oConnection = Me.CommandCollection(0).Connection
oConnection.Open()
Dim oTrans = oConnection.BeginTransaction()
SetTransaction(oTrans)
Return oTrans
End Function
Public Sub SetTransaction(ByVal oTrans As System.Data.Odbc.OdbcTransaction)
For Each cmd In Me.CommandCollection
cmd.Connection = oTrans.Connection
cmd.Transaction = oTrans
Next
End Sub

Resources