I'm having some problems updating the database using Linq...
Public Shared Function Save(ByRef appointment As MyLinq.Appointment, ByRef db As MyEntities) As Boolean
If appointment.id = 0 Then
db.AddToAppointments(appointment)
Else
db.AttachTo("Appointments", appointment)
'db.ApplyPropertyChanges("Appointments", appointment)
End If
Return db.SaveChanges() > 0
End Function
So Insert works fine, i have tryed both lines of code for the update with no sucesss... The first one goes ok but no update is performed, the second one throws an exception...
Can someone point out what i am missing?
EDIT:
Sorry for the late reply... I had some internet connection problems...
I had to "make it work", so now my update code is fecthing the record from the database, updating and then executing "SaveChanges" method. It works but I am not happy having to query the database to perform an Update... If you have any idea how I could do this without an update I would appreciate :)
Chris: It was a nice try, but my refresh method only allows me to choose "RefreshMode.ClientWins" or "RefreshMode.StoreWins" I tried with ClientWins with no success...
Razzie: I am sorry but i did not save the exception and it no longer occurs... It was saying that my record did not have a key associated (or something similar)
Jon Skeet: In Vb.Net we have to specify if the parameter goes ByVal or ByRef, we can't omit like in C#
The code you have doesn't look exactly like what I'm used to (linq to sql), but it does look a little similar; Is this Entity Framework?
I know with Linq to SQL, simply attaching an object to the data context isn't enough, you also have to make sure that the data context knows what the original values are so it knows which columns to update. In Linq to SQL that can be achieved like this:
db.Refresh(RefreshMode.KeepCurrentValues, appointment)
Maybe look around and see if you can achieve something similar in whatever framework you are using.
The ApplyPropertyChanges() call is important otherwise the item you are attaching is assumed to be in an unchanged state. However... for ApplyPropertyChanges to work properly the original object must exist in the ObjectContext which means either querying for it again (which I think you are now doing) or using the same object context that you originally pulled the item from.
Some more info here - http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.applypropertychanges.aspx
Related
One common problem we have in our codebase is that people forget to check if a list is empty before using it in an in clause.
For example (in Scala with Anorm):
def exists(element: String, list: List[String]): Boolean =
SQL("select {element} in {list} as result")
.on('element -> element, 'list -> list)
.as(SqlParser.bool("result").single)
This code works perfectly well as long as list has at least one element.
If it has 0 elements, you get a syntax error, which is weird if you're used to other programming languages that would allow this empty list case.
So, my question is: what's the best way to prevent this error from happening?
Initially, we did this:
def exists(element: String, list: List[String]): Boolean =
if (list.nonEmpty) {
SQL("select {element} in {list} as result")
.on('element -> element, 'list -> list)
.as(SqlParser.bool("result").single)
} else {
false
}
This works perfectly well, and has the added advantage that it doesn't hit the database at all.
Unfortunately, we don't remember to do this every time, and it seems that 1-2 times a month we're fixing an issue related to this.
An alternate solution we came up with was to use a NonEmptyList class instead of a standard List. This class must have at least one element. This works excellent, but again, people have not been diligent with always using this class.
So I'm wondering if there's an approach I'm missing that prevent this type of error better?
It looks like you've already found a way to resolve this problem - you have an exists() function which handles an empty list cleanly. The problem is that people are writing their own exists() functions which don't do that.
You need to make sure that your function is accessible as a utility function, so that you can reuse it whenever you need to, rather than having to rewrite the function.
Your problem is an encapsulation problem: the Anorm API is like an open flame and people can burn themselves. If you rely just on people to take precautions, someone will get burnt.
The solution is to restrict the access to the Anorm API to a limited module/package/area of your code:
Anorm API will be private and accessible only from very few places, where it is going to be easy to perform the necessary controls. This part of the code will expose an API
Every other part of the code will need to go through that API, effectively using Anorm in the "safe" way
Edited to answer my own question. This appears to be a LINQ/VB bug.
A simple LINQ query returning an anomymous type will sometimes change the field names specified in the query so as to capitalize them. Perhaps passing the result of the query as a parameter to a method call:
someThing.someMethod(From someStuff In stuffList _
Select text = someStuff.Name(), _
value = someStuff.Id
)
where someMethod has signature
Public Sub someMethod(ByVal list As IEnumerable(Of Object))
If you step into the execution of someMethod, and then examine the value of list in quickwatch, you may or see the field names as "text"&"value" or "Text"&"Value".
LINQ queries should not be changing the field names as specified in the query, so the correct behavior is fieldnames "text"&"value". Yet production builds of our application have the incorrect capitalization behavior (which can be determined indirectly), and debug builds have shown it both happening both ways at different times and/or for different developers' machines.
I've looked high & low for some feature of LINQ which controls this behavior, but now am virtually certain it is a bug. (msdn forum thread, MS Connect bug page)
This is likely to only cause a problem if you are using reflection, such as type.getfield() such as in
listItem = list.ElementAt(index)
itemTextField = listItem.GetType().GetField("text")
itemText = CType(itemTextField.GetValue(listItem),String)
If this happens to you, the workaround is to use overload of GetField with bindingflags to make it case-insensitive:
itemTextField = listItem.GetType().GetField("text", BindingFlags.IgnoreCase)
It must be pretty rare to encounter this bug, but maybe the next person will spend less time scratching their head if they find this info here.
=========original post===========
Getting different behavior in my debug build environment than in my coworkers' and our production envirnonment, relating to LINQ and reflection...
While running debug build of legacy code, the following code
Dim objectType As Type = obj.GetType()
Dim field As FieldInfo = objectType.GetField(name)
Dim prop As PropertyInfo = objectType.GetProperty(name)
results in Nothing for field & prop.
The value of obj is passed down from above and is the result of a LINQ query (it is a single element of the list generated by the query):
From bpt In CustomBProcessTypes Select text = bpt.Name(), value = bpt.Id
The value of name is also passed from above and is "Text" (note capitalization).
I can examine obj in the debugger and confirm that the fieldnames of the object created by the LINQ query are 'text' and 'value' (note lack of capitalization) which is what I would expect.
So failure to find the field by the capitalized name makes sense. However, our production builds and my coworkers builds do not have this problem.
Because calls to type.getfield(string) are expressly cas-sensitive, the only thing I can think of at this point is there must be some configuration of LINQ relating to auto-capitalization of column/fieldnames, and my environment is not set up the same as the others.
Using visual studio 2012. I don't know much of anything about LINQ, per se.
Anyone have any idea what could be going on here?
(NOTE: if I can get an opportunity, I'll have a coworker step through the relevant code and see if in their environment the object created by the linq query ends up with capitalized field names)
EDIT: I verified with a coworker in his debug build: his LINQ query creates a list of objects with field names "Text" and "Value", but on in my environment the LINQ query ends up with field names "text" and "value". The code is the same, but there must be something about how LINQ is configured in my environment which fails to auto-capitalize those field names, but which happens on their machines and in our production environment.
I suppose it is possible that some compiler settings are resulting in different capitalization. Normally this would make no difference because VB.NET is a case-insensitive language so obj.Text and obj.text both work just as well. But to use case insensitivity in reflection lookups, you need to specify it by including BindingFlags.IgnoreCase in the second parameter of GetField or GetProperty:
Dim field As FieldInfo = objectType.GetField(name,
BindingFlags.Public Or BindingFlags.Instance Or BindingFlags.IgnoreCase)
I'm confused as to where name is coming from, though. Some other code is getting the field name from reflection on the query? I didn't see where this was explained in your question.
I have answered my own question (insofar as is possible). Boils down to a bug in LINQ/vb.net.
Fully explained at top of original post (edited in). Hope this saves someone time in the future.
I'm currently working on my first major project in clojure and have run into a question regarding coding style and the most "clojure-esque" way of doing something. Basically I have a function I'm writing which takes in a data structure and a template that the function will try to massage the data structure into. The template structure will look something like this:
{
:key1 (:string (:opt :param))
:key2 (:int (:opt :param))
:key3 (:obj (:tpl :template-structure))
:key4 (:list (:tpl :template-structure))
}
Each key is an atom that will be searched for in the given data structure, and it's value will be attempted to be matched to the type given in the template structure. So it would look for :key1 and check that it's a string, for instance. The return value would be a map that has :key1 pointing to the value from the given data structure (the function could potentially change the value depending on the options given).
In the case of :obj it takes in another template structure, and recursively calls itself on that value and the template structure, and places the result from that in the return. However, if there's an error I want that error returned directly.
Similarly for lists I want it to basically do a map of the function again, except in the case of an error which I want returned directly.
My question is what is the best way to handle these errors? Some simple exception handling would be the easiest way, but I feel that it's not the most functional way. I could try and babysit the errors all the way up the chain with tons of if statements, but that also doesn't seem very sporting. Is there something simple I'm missing or is this just an ugly problem?
You might be interested in schematic, which does pretty similar stuff. You can see how it's used in the tests, and the implementation.
Basically I defined an error function, which returns nil for correctly-formatted data, or a string describing the error. Doing it with exceptions instead would make the plumbing easier, but would make it harder to get the detailed error messages like "[person: [first_name: expected string, got integer]]".
I've seen this opportunity reported at least half a dozen times with about as many responses.
My problem is, I've got a MySQL database function defined, we'll call it "my_func(int val) returns int", which works fine if I test directly on the database.
I've also gotten it to work with a direct SQL passthrough my repository implementation, which is okay, but I'd rather route it through Hql, for some god-awful reason...
So... I've got a MySQL5Dialect setup to register the function and I'm having some difficulty parsing through the expected conventions.
My understanding is that I need to prefix the function name with "dbo." at some point during the function registration?
Something like this,
//...
RegisterFunction("my_func", new SQLFunctionTemplate(NHibernateUtil.Int32, "my_func(?1)"));
//...
And then through my repository,
var value = repository.FindByHQL<int>("select my_func(2)").Single();
Where FindByHQL returns an IList.
Any thoughts why this wouldn't work.
I'm running the latest WAMP (2.1e I think).
Enough info? Let me know if I can provide any further details.
Thanks,
Michael
select my_func(2)
is not valid HQL, regardless of whether the function is registered or not.
You can use SQL instead if that's your use case.
Post full exception with stack trace if it's not and this was just a simplified example.
Ok, I was rooting around in one of our company apps which is done in VB.net. I'm not familiar with VB.net (I do stuff in C#) so I'm asking this question: Does the code after the clean up comment execute?
Public Function DoesUserHavePermission(ByVal UserID As Integer, ByVal ActionID As Integer) As Boolean
' some extra code re: getting data
Return UserHasPermission
'-Clean Up-
MySqlCommand.Dispose()
MySqlConnection.Dispose()
RowCount = Nothing
End Function
It is my understanding once you say return, you give the calling function control again. Is this a VB.Net oddity which I have to accept or a giant WTF?
The statements after the Clean up comment will not execute. This is a candidate for enclosure within Try/Catch/Finally.
Not unless there's some control logic you omitted in your example
The code should be (the clean up that is) wrapped inside of a finally statement by using a try catch exception:
pseudo:
try
'make conn
catch exception
finally
mysqlCmd.Dispose
....
end try
Is it possible it will still run..possibly...I used to write VB.net and it has been quite some time but I do remember oddities like that. I can't give you a sure answer as this is / was very bad practice. What you can do is clean it up and set some break points in y our code and debug. See if the code comes back to it...
Short answer: The code below the return will never execute.
That looks like translated code. Like someone took a C# snippet from the web and tried to write it in VB for VS 2003 (before VB supported the USING statement, but while C# did).
where the MySqlConnection and MySqlCommand are new'd up should be put in USING blocks and the Dispose() lines turned into END USING.
Where possible, use USING over TRY/FINALLY to ensure cleanup of IDisposable objects.
using mySqlConnection as New SqlConnection(connectionString)
mySqlConnection.Open
using mySqlCommand as New SqlCommand(commandString, mySqlConnection)
'do something that may fail'
return UserHasPermission
end using 'disposes mySqlCommand'
end using 'closes/disposes mySqlConnection'
You can use this pattern for SqlTransactions too. (Place after mySqlConnection.Open)
using myTerribleVariableName as SqlTransaction = mySqlConnection.BeginTransaction
'do something that may fail - multiple SqlCommands maybe'
'be sure to reference the transaction context in the SqlCommand'
myTerribleVariableName.Commit
end using 'disposes. rollsback if not commited'
Oh, and you can delete the RowCount = Nothing statement.
That to me is a giant WTF and a very difficult thing to miss, normally peer code review can catch that, I do not understand why a return from the function is placed earlier on prior to the cleanup. That could have been done during the testing of the code where the programmer was wanting to test the function first and decided to ignore the cleanup code by returning from it quickly enough, I suspect the cleanup code could be lengthy, ie. maybe it is throwing an exception that is not properly caught and wanted to ignore it hence a need to return immediately...That is an (un) intentional side effect of introducing a leak as the resource is not cleaned up properly thereby masking the real problem...that's my take on it.
Hope this helps,
Best regards,
Tom.
The code as presented will not do anything after the return statement. VB.NET and C# are similar in that fashion.
Its possible that this code was written by a VB6 programmer, trusting in old paradigms, or possibly this was the work of the upgrade tool, porting code from VB6 to VB.NET.