Entity Model Not Being Updated on SaveChanges - vb.net

I have a misunderstanding somewhere with the Entity Framework. This code is from my unit testing:
Public Sub UpdateRosterLinkTest()
Dim target As PlayerAdmin = New PlayerAdmin()
target.PlayerAdminManager = playerAdminTestManager
target.Team = playerAdminTestManager.GetAirForceMensBB()
playerAdminTestManager.resetRosterLink(target)
Assert.IsNull(target.Team.RosterLink)
Dim playerAdmin As PlayerAdmin = New PlayerAdmin()
playerAdmin.TeamId = 12434
playerAdmin.RosterLink = "Roster Link"
playerAdmin.UpdateRosterLink()
Dim team As DAL.Team = playerAdminTestManager.GetAirForceMensBB()
Assert.AreEqual("Roster Link", team.RosterLink)
End Sub
I'm creating a PlayerAdmin, which is a model class. target.Team is an Entity object. What I do is reset the RosterLink field in the Team just to make sure our test starts out at the same place. Then I call the UpdateRosterLink() function. That looks like:
Function UpdateRosterLink() As Integer
If (PlayerAdminManager Is Nothing) Then
PlayerAdminManager = New PlayerAdminManager()
End If
Team = PlayerAdminManager.GetTeamByTeamId(TeamId)
Team.RosterLink = RosterLink
Dim numberOfChanges As Integer = PlayerAdminManager.SaveChanges()
Return numberOfChanges
End Function
When I run this code, I can see the changes saved to the SQL Server this pulls from (RosterLink = Roster Link, like I set in the unit test).
However, my unit test is failing, because team.RosterLink is still Nothing. The function GetAirForceMensBB() returns the Team with TeamId = 12434:
Function GetAirForceMensBB() As DAL.Team
Return (From team In Container.Teams Where team.TeamId = 12434).SingleOrDefault
End Function
I'm sure I'm using the entity framework incorrectly and it probably has something to do with the fact that I am calling the PlayerAdminTestManager in different places, but I don't understand why. Although, I set the PlayerAdminManager to be the PlayerAdminTestManager. PlayerAdminTestManager extends PlayerAdminManager, fyi.
Why is team.RosterLink not showing the update from UpdateRosterLink?
Thanks
EDIT
Container is my ObjectContext. This is how I access the information stored in the database. Container.Teams represents my Teams table.

The problem was I was referencing different instantiations of the Container (each manager created its own). Thus, the entity items were not attached to anything.
Doh!

Related

Using Visual Studios 2013 and VB.net, how to capitalize lets in a textfield mixed with numbers

I am and entry level programmer and i have a task that is asking me to modify a page that takes and entry from a textfield that is mixed with letters and numbers. this field is called a "job#" and then the page will search a database for that in particular job. problem is that it only searches it if its in capital letters. need to have it accept caps and lower case letters. it is in VB.net. and i went to the controller and i have this code here
Try
res.success = True
res.message = ""
Dim r = New Objects.Business.Capital.CapitalRequest(jobNumber)
Dim req = New ViewModels.Business.Capital.CapitalRequest(r)
Models.Core.Approvals.AddIApprovableToCache(r)
res.data = req
Return New PCA.Core.Web.JSON.JSONPResult() With { _
.Data = res,
.Callback = callback
}
i tried to tack on "ToUpper() after the (jobnumber) because i thought that is where it takes the number entered and applies it to a variable to search the database for it. but it says that 'ToUpper()' is not a member of 'Trident.Objects.Business.Capital.CapitalRequest' im assuming the parent class doesnt have the package where ToUpper() is ?
i tried to tack on "ToUpper() after the (jobnumber) because i thought
that is where it takes the number entered and applies it to a variable
to search the database for it. but it says that 'ToUpper()' is not a
member of 'Trident.Objects.Business.Capital.CapitalRequest'
Instead of
Dim r = New Objects.Business.Capital.CapitalRequest(jobNumber).ToUpper()
use
Dim r = New Objects.Business.Capital.CapitalRequest(jobNumber.ToUpper())

How can I use (reflection?) to make reusable code for populating object with xml data

I'm using VB.NET 2013 and am trying to write an application that will import (from csv file) customer contact information (for example: CustomerName, ContactLast, ContactFirst, ContactPhn, ContactEmail). There are going to be multiple csv layouts that have to be dealt with, so I'm using an XML file to store the various mappings in.
I'd like to load the defined maps from DataMaps.xlm into DataMap objects then insert those DataMap objects into a list box. I'd like to have them populated with the XML values before I load them into the listbox. I don't expect that there will ever be more than 10 - 15 defined maps, so loading them right away shouldn't be much of a problem with memory or speed (as it will be a locally run application with locally stored xml data).
What I have so far:
Contact Object (short and sweet for this example - not really needed at this point, but given so you can see how the data map is used)
Private mCompany as String
Private mLastName as String
Private mFirstName as String
Private mPhone as String
Private mEmail As String
<... Support Get/Set items (Properties are same as private variables; minus the leading "m") ...>
DataMap Object (short and sweet again for this example)
Private mDataMapName as String
private mCompany_Col as Integer
private mLastName_Col as Integer
private mFirstName_Col as Integer
private mPhone_Col As Integer
private mEmail_Col As String
<... Support Get/Set items (Properties are same as private variables; minus the leading "m") ...>
"Standard" CSV layout
"Company ABC", "Jones", "June", "515-874-0098", "JJ#ABC.COM"
"Company EFG", "Williams", "Alan", "515-874-2887", "alan#efg.com"
The DataMap for this layout would be:
<Map>
<DataMapName>Standard</DataMapName>
<Company>1</Company>
<LastName>2</LastName>
<FirstName>3</FirstName>
<Phone>4</Phone>
<Email>5</Email>
</Map>
"Not Standard 01" CSV Layout
"Jones", "June", "Company ABC", "515-874-0098", "JJ#ABC.COM"
"Williams", "Alan" "Company EFG", "515-874-2887", "alan#efg.com"
The DataMap for this format would be:
<Map>
<DataMapName>Not Standard 01</DataMapName>
<Company>3</Company>
<LastName>1</LastName>
<FirstName>2</FirstName>
<Phone>4</Phone>
<Email>5</Email>
</Map>
I'm just picking up VB.NET again and am not comfortable with determining the "best" techniques to use while reading data from the .xml file (I can retrieve a list of s using LINQ currently) and populating my DataMap object. I know I can do it by using each individual property to set the values; but I'd like to write generic (looping) code as this app may be rewritten with changes to the DataMap requirements as well as using this in other application instances.
Currently, I am able to create a new element and add it to the DataMaps.xml file. I can then read those changes correctly.
Where I'm stuck is writing a 'generic' populateMap(mapName As String) function. Where I am right now, I can get the map (as an Enumeration of XElement) and then individually look at each property and store it into a new instance of a DataMap object:
Dim dm as New DataMap
dm.DataMapName = map.Element("DataMapName").Value
dm.Company_Col = map.Element("Company_Col").value
dm.LastName_Col = map.Element("LastName_Col").value
dm.FirstName_Col = map.Element("FirstName_Col").value
...
But, I'd like know if it's possible to create something like: (pseudocode)
Dim dm As new DataMap
Dim myInstance As New DataMap
Dim myFields As FieldInfo()
Dim myType As Type = GetType(DataMap)
try
myFields = myType.GetFields(BindingFlags.NonPublic)
for each element in map.Elements
Dim f as FieldInfo = GETType(DataMap).GetField(field.name)
dm.(some sort of reference to a FieldInfo() column name, or something) = element.f
(this would look like: dm.Company_Col = element.Company_Col (or a variable referencing the private value "mCompany_Col")
next
catch ...
Finally ...
End Try

Context issue in IHttpHandler

Sorry, this can be a basic question for advanced VB.NET programmers but I am a beginner in VB.NET so I need your advice.
I have a web application and the login is required for some specific pages. To check if the user is logged in, the old programmer used this technique:
Dim sv As New WL.SessionVariables(Me.Context)
If Not (sv.IsLoggedIn) Then
Response.Redirect(WL.SiteMap.GetLoginURL())
End If
Well, I have to use this Logged In checking in a handler done by me and I tried this:
Public Class CustomHandler
Implements System.Web.IHttpHandler, IReadOnlySessionState
Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim sv As New WL.SessionVariables(context)
If Not (sv.IsLoggedIn) Then
context.Response.Write("No access unless you're the CEO!!!" & sv.IsLoggedIn)
ElseIf sv.IsLoggedIn Then
DownloadFile(context)
Else
End If
End Sub
//other code
End Class
Well, the "is logged in" checking is always false (even after I login) and I think it's an issue with the context. So all the other pages works fine with logging checking but this handler have this specific issue.
Can you guys give a helping hand?
UPDATE:
The logged in is done trough this method:
Public Sub SetCreditialCookie(ByVal accountID As Integer)
Me.AccountID = accountID
m_context.Session.Item("loggedInAccount") = accountID
m_context.Response.Cookies.Add(New System.Web.HttpCookie("account_id", CStr(m_context.Session.Item("account_id"))))
m_context.Response.Cookies("account_id").Expires = DateTime.Now.AddDays(5)
End Sub
and to check it it's logged in, this method is called:
Public Function IsLoggedIn() As Boolean
If Not m_context.Session.Item("loggedInAccount") Is Nothing And Me.AccountID = m_context.Session.Item("loggedInAccount") Then
Return True
Else
Return False
End If
End Function
UPDATE 2:
- debugging the code shown that there were multiple kind of logins and I was checking the wrong one with the session.
Due to the use of IReadOnlySessionState, is it possible that the SessionVariables class attempts in some way to modify the Session, which in turn causes an error (possibly handled and not visible to you).
If this is the case it could mean that the IsLoggedIn property is not correctly initialised, or does not function as expected?
Do you have access to the code for the class. If so, try debugging it to see what is happening.

How do I check whether a Linq-to-SQL object is already attached to a DataContext?

I have an object that may have been inflated via a plain old DataContext, or may just have been new-ed up with just its .ID property set. There's no way to know for sure. I'm looking to rehydrate the entire object from whatever is in the database. If the object was new-ed up, I can call .Attach() on the table object and refresh from the Data Context with no trouble. But, if the object was already inflated from the DataContext I get the error: "Cannot attach an entity that already exists.". There's no timestamp field or anything like that - just an integer primary key being used to control the rehydration. I'd like to know if there's a way to conditionally attach. Here's the code - it works the way I want it to, but this seems a hackish way to go about it:
' myDC is a shared instance of a vanilla DataContext...
' myObj is an instance of a linqed-up `SomeLinqObject`
Dim tbl = myDC.GetTable(Of SomeLinqObject)()
Try
tbl.Attach(myObj) ' <-- Wish I could just TryAttach() here!
Catch ex As Exception
If ex.Message = "Cannot attach an entity that already exists." Then
' Do nothing
Else
Throw
End If
End Try
myDC.Refresh(RefreshMode.OverwriteCurrentValues, myObj) ' Rehydrate
-- EDIT --
Thanks to Isaac's answer, here's the revised code:
Dim tbl = myDC.GetTable(Of SomeLinqObject)()
Dim isAttached = (tbl.GetOriginalEntityState(myObj) IsNot Nothing)
If Not isAttached Then tbl.Attach(myObj)
myDC.Refresh(RefreshMode.OverwriteCurrentValues, myObj) ' Rehydrate
GetOriginalEntityState(T entity) on Table -might- be what you're looking for. If you pass it an entity that you've loaded from the context, it returns the original version of the entity held in the context. If you pass it a new entity (or I believe one simply not sourced from that context), it returns null.
var context = new DataClasses1DataContext();
var person = context.Person.First();
var isAttachedToContext = context.Person.GetOriginalEntityState(person) != null; // returns true
var isNewEntityAttachedToContext = context.Peoples.GetOriginalEntityState(new Person()) != null; // returns false
Apologies - answer is in C# but I hope you get the gist!

Return type from DAL class (Sql ce, Linq to Sql)

Using VS2008 and Sql CE 3.5, and preferably Linq to Sql.
I'm learning database, and unsure about DAL methods return types and how/where to map the data over to my business objects: I don't want direct UI binding.
A business object class UserData, and a class UserDataList (Inherits List(Of UserData)), is represented in the database by the table "Users". I use SQL Compact and run SqlMetal which creates dbml/designer.vb file. This gives me a class with a TableAttribute:
<Table()> _
Partial Public Class Users
I'm unsure how to use this class. Should my business object know about this class, such that the DAL can return the type Users, or List(Of Users) ?
So for example the "UserDataService Class" is a part of the DAL, and would have for example the functions GetAll and GetById. Will this be correct : ?
Public Class UserDataService
Public Function GetAll() As List(Of Users)
Dim ctx As New MyDB(connection)
Dim q As List(Of Users) = From n In ctx.Users Select n
Return q
End Function
Public Function GetById(ByVal id As Integer) As Users
Dim ctx As New MyDB(connection)
Dim q As Users = (From n In ctx.Users Where n.UserID = id Select n).Single
Return q
End Function
And then, would I perhaps have a method, say in the UserDataList class, like:
Public Class UserDataList
Inherits List(Of UserData)
Public Sub LoadFromDatabase()
Me.clear()
Dim database as New UserDataService
dim users as List(Of Users)
users = database.GetAll()
For each u in users
dim newUser as new UserData
newUser.Id = u.Id
newUser.Name = u.Name
Me.Add(newUser)
Next
End Sub
End Class
Is this a sensible approach? Would appreciate any suggestions/alternatives, as this is my first attempt on a database DAL.
cheers!
EDIT:
Seems I have problems with the query/return types of GetAll() and GetAllById().. Not sure how to do this..
Open Visual Studio.
Open the server connections tab and connect to your SQL server.
In your project, add a new Linq To SQL Data Context. This will add a new file. Once this is open in the designer, drag and drop the tables from your database into the SQL Data context.
At this point, you can now go to your code and say.
NameOfYourDataContext dc = new NameOfYourDataContext();
var query = from row in dc.table
where property == 0 //Filter if needed
select row;
//OR var query = dc.table.where(row => row.Property == 0);
int i = 0;
foreach(var row in query)
{
row.property = i++;
}
dc.SubmitChanges();
If you are really trying to control the class that is created then I recommend that you look into the SQL Metal tool which can create data contexts from an xml file.