Can I call SaveChanges when using raw SQL Query in EF6 - vb.net

I want to use sql raw query for better performance.
I was wondering if I could use context the same way as if I committed a query with linq. If I bind collection to dgv.DataSource and made some (update) could I call db.SaveChanges() to store the data in the database.
Example:
Using context = New BloggingContext()
Dim blogs = context.Blogs.SqlQuery("SELECT * FROM dbo.Blogs").ToList()
datagridview1.dataSource = blogs
' if I made some changes in datagridview1 could I
' use SaveChanges to commit any changes on button click
context.SaveChanges()
End Using

The DbSet.SqlQuery method returns object that are tracked by the context :
By default, the entities returned are tracked by the context (MSDN)
(note that Database.SqlQuery results never tracked by the context)
If you change your entities using Entity Framework the SaveChanges method will persist changes.
Using context = New BloggingContext()
Dim blogs = context.Blogs.SqlQuery("SELECT * FROM dbo.Blogs").ToList()
blogs.First().Title = "new Title"
context.SaveChanges() ' new Title will be persisted on database
End Using
By the way, depending on the kind of datagridview you are using (webform, winform, WPF, etc.), you will have to attach the modified entities to the context that will be used to save changes.

Related

LINQ program NOT populating the database

I am quite new to LINQ but some help from a field has produced the following code that works OK; but does not write the data to the SQL Server database records.
Public Function Error_Log_Add(ServiceDateRec As VariantType, Seq As VariantType, RosterID As VariantType, ContactID As VariantType, MessageID As VariantType)
'
' Add Error Message to a Service
'
Error_Log_Add = False
Dim context As RosterMaster_Rostering = Me.RosterMaster_Rostering
Dim newErrorDataSet As RosterMaster_Rostering.ErrorLogDataTable = context.ErrorLog
Dim newErrorLogRow As RosterMaster_Rostering.ErrorLogRow
newErrorLogRow = newErrorDataSet.NewRow()
newErrorLogRow.ServiceDateID = ServiceDateRec
newErrorLogRow.Seq = Seq
newErrorLogRow.Roster_Required = RosterID
newErrorLogRow.PostID = ContactID
newErrorLogRow.Error_Message = MessageID
newErrorDataSet.Rows.Add(newErrorLogRow)
newErrorDataSet.AcceptChanges()
MsgBox("Inserted" + newErrorDataSet.Rows.Count.ToString())
End Function
Can someone point me in the right direction please.
You're so new to LINQ that you haven't even started with it apparently, because there is no LINQ at all in that code. You are using a typed DataSet, which is simply ADO.NET.
The problem is that you're not actually trying to save anything to the database. You need to call Update on a table adapter for that to happen, which is nowhere to be seen in that code. You seem to be under the impression that calling AcceptChanges will save something but it won't. The DataRows in your DataTable each track their own changes and AcceptChanges basically tells them to stop doing so because those changes have been saved. You haven't actually done the saving though. You need to call Update on the appropriate table adapter and it will save the changes and then implicitly call AcceptChanges.

Updating Datatable as Datasource

I'm using a data table as a data source for a data grid in VB.NET.
Public Property InterimLotTable As DataTable
uxDataGridAuditSamplerView.DataSource = SamplerParent.InterimLotTable
But when I update the SamplerParent.InterimLotTable its not reflected in my dataGrid.
Here is the code where I update the Datatable.
Dim sql = String.Format("select * from CAMS.VW_BL_TAS_InterimLotData where PARENTLOT = '{0}'", ParentLot)
Dim dynaset = db.CreateDynaset(sql, DBWrapper.DynasetOptions.ORADYN_READONLY)
InterimLotTable = dynaset.CopyToDataTable()
I thought that with the databinding when I made changes to the InterimLotTable the datagrid would be updated automatically.
You're not updating InterimLotTable, you're replacing it - i.e. the property now returns a different object.
The controls that are bound to the old object don't know anything has happened, as the object they have a reference to, hasn't changed.
You could use an intermediate BindingSource, or raise an event so the UI can choose to rebind as appropriate

The data source does not support sorting

I have a Dynamic Data LINQ to SQL ASP.Net Website in VB.NET, and am having a little trouble with Sorting of my GridView and a Search routine I have implemented. On Page_Load, the GridView is sorted by a field (Departments.department) in ASC order. However, when I perform a search using the code below, I get an error
The Data Source Does Not Support Sorting.
I'm assuming the problem comes when the Page_Load event tries to sort the data after a Search is made, because of the DataSource/ID.
Dim button = DirectCast(sender, Button)
If button.ID = btnMultiColumnSearchClear.ID Then
txbMultiColumnSearch.Text = [String].Empty
Else
Using Data As New wcPhonesDataContext()
Dim EmployeeNameString As String = txbMultiColumnSearch.Text
Dim SearchResults = Data.Employees.Where(Function(Employees) Employees.Employee.Contains(EmployeeNameString))
GridView1.DataSourceID = ""
GridView1.DataSource = SearchResults
GridView1.DataBind()
End Using
End If
SOLVED, but now I have a new problem, here is the code I used to solve this issue...
Dim button = DirectCast(sender, Button)
If button.ID = btnMultiColumnSearchClear.ID Then
txbMultiColumnSearch.Text = [String].Empty
Else
Using Data As New wcPhonesDataContext()
Dim EmployeeNameString As String = txbMultiColumnSearch.Text
Dim SearchResults = Data.Employees.Where(Function(Employees) Employees.Employee.Contains(EmployeeNameString))
GridView1.Sort("", SortDirection.Ascending)
GridView1.DataSourceID = ""
GridView1.DataSource = SearchResults
GridView1.DataBind()
End Using
End If
I have created a new error though. It occurs if I perform a second search without going BACK to the Employees table.
'GridView1' fired event Sorting which wasn't handled.
If you use a SqlDataSource and connect the gridview to the data source with a datasourceid, then sorting is done for you magically. You don't have to do anything to support it.
But if set the datasource to some object that you have created in code, sorting does NOT magically happen for you. When the user clicks on a column head, this fires an OnSorting event. You have to write code to handle the event. Typically this mean regenerating the data in the desired order, or regenerating the data and then sorting it.
For example, if you generate the data with a SQL query, I sometimes create a function that runs the SQL query and returns a DataSet. This function takes the sort field as a parameter, which it pastes into the SQL query. Then for the initial display call this function passing in the default sort order, and for the OnSorting call this function passing in the desired sort field.

Adding a new object to context

So apparently I don't understand EF well enough yet. Someone here at SO suggested I shouldn't keep a context object open for the life of my application, so I changed things slightly and now here is how it is currently working:
I read required data from the DB using EF and store it in an ObservableCollection(Of MyEntity).
The application keeps adding new objects to this collection, modifying/deleting existing objects in the ObservableCollection.
Upon application exit or Save button, I try to submit changes back to the DB, but apparently cannot. Here's the submission code.
For Each entity In MyObservableCollection
If entity.EntityState = EntityState.Added OrElse entity.EntityState = EntityState.Detached Then
Dim key = context.CreateEntityKey(entitySetName, entity)
entity.EntityKey = key
context.FilmTypes.Attach(entity)
ElseIf entity.EntityState = System.Data.EntityState.Modified Then
Dim originalItem As Object = Nothing
Dim key = context.CreateEntityKey(entitySetName, entity)
If context.TryGetObjectByKey(key, originalItem) Then
context.ApplyCurrentValues(key.EntitySetName, entity)
End If
End If
Next
context.SaveChanges(SaveOptions.AcceptAllChangesAfterSave)
EF tells me that there is already an object with the same key. My PK column is defined as Identity in the Model, so I expect it to auto-generate a temporary key (just like old good DataSets did).
How exactly do we work in "disconnected" mode in EF?
Found it myself. The code for Modified state is correct. For new objects, it should be like this:
If entity.EntityState = EntityState.Added OrElse entity.EntityState = EntityState.Detached Then
context.FilmTypes.AddObject(entity)
No need to specify key parameter. EF will take care of it.

Active Record with Entity Framework

I'm working on a project that was built using ADO.NET (raw sql) and Active Record pattern. I am slowly moving it away from ADO.NET to Entity Framework Code First 4.3.
Here is an example of the pattern. The interface is a static Load and an instance Save (and Delete -- not shown).
Public Class Part
Public Property Id as Integer
Public Shared Function Load(_id As Integer) As Part
Using context As New DataContext()
Return context.Find(_id)
End Using
End Function
Public Sub Save()
Using context As New DataContext()
If Id = 0 Then
context.Parts.Add(Me)
Else
context.Entry(Me).State = Data.EntityState.Modified
End If
context.SaveChanges()
End Using
End Sub
End Class
I realize Active Record is not ideal for EF but I'd like to make it work to remove all of the ADO.NET code while not touching the rest of the code.
This mostly works, but I've run into an issue I don't know how to solve. In order to keep Foreign Keys in sync we handle it like such:
Public Sub Save()
ParentPart = Part.Load(ParentPartId)
ChildPart = Part.Load(ChildPartId)
Using context = New iTracContext()
If bid = 0 Then
context.BillOfMaterials.Add(Me)
Else
context.Entry(Me).State = Data.EntityState.Modified
End If
context.SaveChanges()
End Using
End Sub
This makes sure EF doesn't complain that we have non-matching relationships -- the Id always wins.
The issue is that its throwing an exception now when I save.
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
This is thrown from the line:
context.Entry(Me).State = Data.EntityState.Modified
How is anything in the ObjectStateManager for this context? It is brand new and should be empty, no?
If I remove the two Part.Load(...) lines it works fine.
Is there some type of change tracker that lives outside the context that I'm not aware of? That seems like it would kill any attempt at the Active Record pattern.
I'm also open to any suggestions on how to make Active Record work with EF. The context.Entry line is terrible but I don't know what else to do.
Telling me not to do Active Record isn't helpful, but feel free.
I believe Entity Framework may still be tracking the object from the context you loaded it from, because you create a new context for each Load and Save call. If this is the case, try detaching the objects after you load them:
Public Shared Function Load(_id As Integer) As Part
Using context As New DataContext()
Part part = context.Find(_id)
context.Entry(part).State = EntityState.Detached ' Detach from the initial context
Return part
End Using
End Function