Restricting to update a field in Entity Data Model in Silverlight - entity-framework

I am having a field in the database "IsActive" which is "Null" by default. Now I want to update the field once and set it to true. Now once the field is set to true I need to prohibit further modifications to it. Any help please!

For each property RIA Services creates in an entity, RIA Services also creates several partial method stubs that are called when the property value is changing for you to override, e.g. For your IsActive property, RIA Services generates:
Private Partial Sub OnIsActiveChanging(ByVal value As Boolean)
End Sub
Private Partial Sub OnIsActiveChanged()
End Sub
You'll find these stubs in the file that RIA Services creates when you compile (in the Generated_Code folder in your Silverlight project folder; it won't be included in the project itself).
There is no way to "cancel" the change, but you can put a little logic in to set the value back yourself, e.g. in a partial class for your entity:
Private _setBackToTrue As Boolean
Private Sub OnIsActiveChanging(ByVal value As Boolean)
If Not value AndAlso Me.IsActive Then
_setBackToTrue = True
End If
End Sub
Private Sub OnIsActiveChanged()
If _setBackToTrue Then
Me.IsActive = True
_setBackToTrue = False
End If
End Sub

Related

VBA class instantiation and scope

I want to create class that is intended to serve as configuration management and serving helper. It would store some basic connection settings in XML file, read it to it's own properties and serve to any other module, form, object etc.
I've created a class like following:
Option Compare Database
Option Explicit
Private mstrSqlServerName As String
'...
Public Property Get SqlServerName() As String
SqlServerName = mstrSqlServerName
End Property
'...
Private Sub Class_Initialize()
readConfigFile
End Sub
Private Function loadConfigFile() As MSXML2.DOMDocument60
On Error GoTo FunctionError
Dim XMLFileName As String
Dim objRoot As IXMLDOMElement
Dim strMsg As String
Dim oXMLFile As MSXML2.DOMDocument60
'Open the xml file
Set oXMLFile = New MSXML2.DOMDocument60
XMLFileName = (Application.CurrentProject.Path & "\config.xml")
With oXMLFile
.validateOnParse = True
.SetProperty "SelectionLanguage", "XPath"
.async = False
.Load (XMLFileName)
End With
Set loadConfigFile = oXMLFile
End Function
Public Sub readConfigFile()
Dim oXMLFile As MSXML2.DOMDocument60
Set oXMLFile = loadConfigFile
mstrSqlServerName = oXMLFile.selectSingleNode("//config/database/SqlServerName").Text
End Sub
I've tested my class in intermediate window and everything works flawlessly. Then
I've created hidden form to instantiate the class like follows:
'frmYouShouldNotSeeMe
Option Compare Database
Option Explicit
Public configuration As clsConfiguration
Private Sub Form_Load()
Set configuration = New clsConfiguration
MsgBox Prompt:=configuration.SqlServerName
End Sub
Now, from other module/form/report etc. i wanted to call configuration item with:
MsgBox configuration.SqlServerName
But when I'm trying to compile my project it says "compile error, variable not defined". In short: I cannot find a way to use instantiated (named) object properties from other objects of database. They just don't know anything about it's existence. In the intermediate window everything works, I can instantiate object and call GET functions. What did I do wrong? Probably it's just what OOP design brings and I just don't understand that. What is the best way to achieve this goal?
You can add two public functions to your class.
Like this:
Public Function SqlServerName() As String
SqlServerName = oXMLFile.SelectSingleNode("//config/database/SqlServerName").Text
End Function
Public Function GetConfig(strNode As String, strValue As String) As String
Dim strXPATH As String
strXMPATH = "//config/" & strNode & "/" & strValue
GetConfig = oXMLFile.SelectSingleNode(strXMPATH).Text
End Function
Now in code you can use:
Msgbox configuration.SqlServerName
Or to get any config you can use the helper functon with 2 params
Msgbox configuration("database","SqlServerName")
So, the public members of the class HAVE to be written by you. It does not by "magic" or out of the blue expose information from that class. You can use public functions, and they will appear as inteli-sense when you create such public functions. (they become properties of the class). So, your syntax does not work because you don't have a public function (or a property get) that exposes what you want. You can use a property let/get, but a public function also works very well as the above shows.
So, either make a public function for each "thing" (node) you want to expose, or use the helper function above, and you can pass the key + node value with the function that accepts 2 parameters. Both the above will become part of the class, show inteli-sense during coding - you are free to add more public members to the class as per above.
#Edit
the sample code shows this:
Set configuration = New clsConfiguration
MsgBox Prompt:=configuration.SqlServerName
it needs to be this:
dim configuration as New clsConfiuration
MsgBox Prompt:=configuration.SqlServerName
You could on application startup setup a GLOBAL var called configueration, and thus not have to declare the configeration variable in the forms code.
You thus need a global var - set it up in your startup code before any form is launched.
So in a standard code module, you need this:
Public configuration as new clsConfiguration
But, your screen shot of the code is MISSING the create of the configuartion variable.
And your provided code has this:
Set configuration = New clsConfiguration
MsgBox Prompt:=configuration.SqlServerName
So where and when did you define configuration as global scoped variable?
You either have to use LOCAL scope to the form (in fact your on-load event)
dim configuration as New clsConfiuration
MsgBox Prompt:=configuration.SqlServerName
Or, you can as noted, declare "configuration" as a public global varible in a starndard code module (not forms module, and of course not a class module).
if you use the "new" keyword, then you can use this:
Public configuration as New clsConfiuration
The above can be placed in any standard code module - it will be global in scope.
With above, then in the forms load event, this will work:
MsgBox Prompt:=configuration.SqlServerName
As configuration is declared in frmYouShouldNotSeeMe you can refer to the form to access the variable, as long as the form is open.
Debug.Print Forms("frmYouShouldNotSeeMe").configuration.SqlServerName

entity framework "Code first from Database" ObservableCollection and .t4 file

My ultimate aim is to have an EF model working alongside a sqlite local db. The dev is going to involve a lot of modification of the db and thus a lot of updating of the model. The gui will use a lot of Master-Detail views to edit the data.
I've figured that in order to get master-detail views working, you have to replace ICollection and HashSet with ObservableCollection. I achieve this via a custom ObservableListSource class.
I've given up on trying to achieve this via "database first." There's to many limitations/omissions on the "update model from database" option. For example, it doesn't update any changed fields or relationships, meaning you have to delete and re-impot the whole model again. You then have to change the .tt files to change Hashset and ICollection to the ObservableListSource. Overall the method just feels too shonky and hit and miss.
Thus, looked into the "Code first from Database" option. On initial tests appears a lot more robust and reliable than database first. However, it doesn't generate and .tt files, which would allow you to change all of the ICollection entries in the generated classes.
I did find this:
Changing the generated classes from "Code First From Database" EF6
And successfully downloaded the .t4 file. I managed to get HashSet replaced by ObservableListSource by amending some code. Extract of the fuill entity.t4 file:
Public Sub New()
<#
foreach (var collectionProperty in collectionProperties)
{
#>
<#= code.Property(collectionProperty) #> = New ObservableListSource(Of <#= code.Type(collectionProperty.ToEndMember.GetEntityType()) #>)()
<#
}
#>
End Sub
Now this works..when the classes/entities are generated, the replacement occurs correctly. However, I cannot get the same to work for ICollection. An example of how this in generated in the entity class:
<Table("dbControl")>
Partial Public Class dbControl
Public Sub New()
dbController_Controls = New ObservableListSource(Of dbController_Controls)()
End Sub
Public Property ID As Long
<StringLength(2147483647)>
Public Property Name As String
Public Property ControlTypeID As Long?
Public Property ControlAssociationID As Long?
Public Overridable Property dbControlAssociation As dbControlAssociation
Public Overridable Property dbControlType As dbControlType
Public Overridable Property dbController_Controls As ICollection(Of dbController_Controls)
End Class
The relevant part of the EntityType.t4 appears to be:
foreach (var navigationProperty in entityType.NavigationProperties)
{
if (!first)
{
WriteLine(string.Empty);
}
else
{
first = false;
}
#>
Public Overridable Property <#= code.Property(navigationProperty) #> As <#= code.Type(navigationProperty) #>
<#
}
#>
End Class
However, there is no specific reference in the file to ICollection anywhere. Therefore a straight replace doesn't seem to be possible, unlike HashSet
Does anyone have any ideas?
I'm coming close to ditching Entity Framework all together tbh, as it's proving to be a little temperamental/infuriating! Any help appreciated

Custom events in Access database

I tried this in an Access newgroup, and got over a hundred views, but not a single response, so I hope it fares better here.
I'm trying to get a grip on custom events in VBA. I've scoured endless sources on the net, studied my manuals, experimented with everything I can think of, and success is still somewhat tenuous.
Exactly what I hope to accomplish is not all that complicated, and seems like it should be ideal for custom event routines. I have main forms with comboboxes and listboxes fed from tables or queries. The user can open various dialog boxes and do things to modify the tables. When that activity is done, I would like to requery the box(es) affected by any such activity. The way I have done it in the past was to set a global 'SourceHasChanged' Boolean variable and check its status upon returning from the dialog. It works, but is a bit unwieldy, so I decided to try replacing this with custom events.
Hours of studying and endless dead-end tries and repeats have finally produced the following bits of code. They do nothing spectacular. There is a table called T. The dialog form adds records on each click of the Add button. The main form has another button that deletes all but the first record in the table. Each set of code is supposed to fire an event indicating that the listbox is to be requeried. The code in the main form does okay, but the code in the dialog refuses to activate the StalaSeZmena event. Obviously (I think, anyway), that's because the dialog from creates a new instance of the class module. But I have to have a WithEvents variable in the dialog form. If I don't, I would have to make a reference to the WithEvents variable in the main form. Requiring forms to know that much about each other is exactly back-asswards from what I thought the custom event route was going to accomplish. It would be easier and less confusing to just stay with a global status variable.
Class Module [Zmena]
Public WithEvents Udalost As HlaseniZmeny
Private Sub Udalost_StalaSeZmena()
Form_Mane.lstS.Requery
Debug.Print "Requery via class module"
End Sub
Class Module [HlaseniZmeny]
Public Event StalaSeZmena()
Public Sub OhlasitZmenu()
RaiseEvent StalaSeZmena
End Sub
Regular Module
Public chg As Zmena
Form Code [Mane]
Private WithEvents chgMane As HlaseniZmeny
Private Sub cmdCallDialog_Click()
DoCmd.OpenForm "Dia", acNormal, , , , acDialog
End Sub
Private Sub cmdShrinkT_Click()
CurrentDb.Execute "Delete * From T Where Pole1 <> 'A'"
chgMane.OhlasitZmenu
End Sub
Private Sub Form_Open(Cancel As Integer)
Me.Label1.Caption = Me.SpinButton1.Value
Set chg = New Zmena
Set chgMane = New HlaseniZmeny
Set chg.Udalost = chgMane
End Sub
Private Sub chgMane_StalaSeZmena()
lstS.Requery
Debug.Print "Requery from event on main"
End Sub
Form Code [Dia]
Private WithEvents chgDia As HlaseniZmeny
Private Sub cmdAdd_Click()
CurrentDb.Execute "Insert Into T (Pole1) Values(chr(asc('" & DMax("Pole1", "T", "Pole1") & "')+1))"
Set chgDia = New HlaseniZmeny
Set chg.Udalost = chgDia
chgDia.OhlasitZmenu
Set chgDia = Nothing
End Sub
It's functional, but feels awkward, clunky and not at all intuitive, like scratching my left ear with my right foot. The class module has a reference to the main form, which violates the principle of encapsulation, but I found no way to make the dialog form activate the event routine in the main form. I have to have a global variable to link the two WithEvents variables to, or nothing works, but this also violates encapsulation.
Is this really how these constructs are supposed to operate, or have I accidentally stumbled onto a Mad-Max version that happens to work, but isn't the proper way to build such procedures?

Regarding Eclispe EMF Command Frame WorK

Can any one tell me how to use AddCommand rather than `SetCommand" to do the following.
I have a class like this:
class Profile {
List achievements;
List grades;
List extracurrics;
}
Now, suppose I need to add a grade object to this Profile object,how can I achieve this by using AddCommand only
SetCommand is basically used to set values in EMF model, and AddCommand is used to modify collection values inside EMF model, so in general it should not be a problem to use AddCommand.
You can create new AddCommand using static creation function in AddCommand:
AddCommand.create(EditingDomain domain, EObject owner, EStructuralFeature feature, java.lang.Object value)
Explanation of given values:
domain: the editing domain your model lives in
owner: element you are doing the modifications to
feature: feature in model, that should be given to you by the EPackage of your model.
So this case is the Grades list feature
value: the new object you add to the list
There are many different create helpers in add command, so if you need to define index to list, it is also doable.
I don't have EMF running here, so I cannot provide any direct sources, but let me know if that didn't do the trick.
It should look something like this:
Profile p = ...;
Grade g = ...;
Command add = AddCommand.create(domain,p, YourProfilePackage.Literals.PROFILE__GRADES, Collections.singleton(g));
where YourProfilePackage should be in the code generated automatically from your EMF model.

Different Connection Strings with Entity Framework based on Context

I have a web forms application that uses entity framework, the application is deployed on a development box, my local machine and a production box. Each of these have different connection strings.
What is the best way of handling this.
I use TFS Build Server to deploy to development and take the result of that build zip it and copy it to production manually.
I also use Web Deployment Projects if that helps
What I was doing before was when the ORM started it would choose a connection string based on the name of the root folder. With Entity Framework I don't know how to do this without having to set it on every page.
We have something vaguely similar, I created a class to wrap the EntityContext object, which sets the connection string appropriately - you'd need something similar, based on how you set your connection string:
Public Class MyEntityModel
Private _dataContext As Entities
Public Sub New()
Dim entityBuilder As New EntityConnectionStringBuilder()
entityBuilder.ProviderConnectionString = MyApplicationConnectionString
entityBuilder.Metadata = "res://*/"
entityBuilder.Provider = "System.Data.SqlClient"
_dataContext = New Entities(entityBuilder.ConnectionString)
End Sub
Public Function DataContext() As Entities
Return _dataContext
End Function
End Class
FYI You can use config transformations now in VS 2010:
http://msdn.microsoft.com/en-us/vstudio/Video/ff801895