In both deletes and updates there's an assumption that you have to retrieve the corresponding entity object from the database. With an update, you pull back the object so that you can set its properties; with a delete, you retrieve the object so that you can pass it to the corresponding collection's Remove method. That delete code might look like this, for example:
Dim cust As Customer
cust = db.Customers.Find("A123")
db.Customers.Remove(cust)
db.SaveChanges
You don't have to actually need to make that first trip to the database. For a delete, for example, all you have to do is convince Entity Framework's change tracking mechanism that you've deleted the object ... and that just means that you have to remove an object with the right values in the primary key properties. This code, for example:
Dim cust As New Customer
cust.CustId = "A123"
db.Customers.Attach(cust)
db.Customers.Remove(cust)
db.SaveChanges()
will delete Customer A123 from the database without having to retrieve it.
Posted by Peter Vogel on 06/03/20160 comments
You have a List of one object but you really want to have a List of some other object. If it was a single object, you could cast from one to the other with a single line of code:
Dim pCust As PremiumCustomer = New PremiumCustomer
Dim cust As Customer
cust = pCust
But, because you have a collection of objects, you might assume that you have to write a loop and transfer your objects from one List to the other individually. The good news is that you can do that in one line of code using two LINQ functions: Cast and ToList. Here's the one line solution that creates a list of Customers from a list of a derived class, PremiumCustomers:
Dim pCusts As List(Of CustomerPremium) pCusts = GetPremiumCustomers()
Dim custs As List(Of Customer)
custs = pCusts.Cast(Of Customer)().ToList()
Unlike some "clever" LINQ solutions this one is, I think, actually readable. Under the hood, of course, that loop is probably still being created by LINQ and the compiler…but you don't have to write it. Besides, with this single line of code, the compiler might even be able to invoke some clever optimization to speed up the process.
I didn't come up with this myself: If you're interested there are six more useful LINQ tips where this one came from, all thanks to Igor Ostrovsky.
Posted by Peter Vogel on 06/01/20160 comments
It doesn't show often in the columns I write here, but I'm a big fan of organizing large projects into files. You can, of course, create those folders in Solution Explorer, which adds the folders to your file system.
But, if you use Class View, you know that your Solution Explorer folders don't show up there. As the number of classes in your application starts to increase, the usefulness of Class View starts to diminish. If you want, though, you can also organize Class View into folders … and those folders don't have to match your Solution View folders.
It's not obvious how to do this -- right-clicking in Class View and picking Add from the submenu won't give you a folder option, for example. Instead, you need to click the Add Folder button in the top left-hand corner of Class View. Once you've created your folder, you can drag classes into it (still in Class View, of course). You can also create subfolders (right-clicking on a folder will give you a New Folder option).
These folders only exist in your solution's information file (the .sou file) and aren't added to your file system.
Posted by Peter Vogel on 05/20/20160 comments
By default, any values that you pass to a method in a parameter are protected from change inside the method. In this code, for example, I know that my variable NotChanged can't be different after I call the method. In this code, the test on the last line is guaranteed to be true:
string NotChanged;
NotChanged = "Fred";
MyOrdinaryMethod(NotChanged);
if (NotChanged == "Fred") ...
That is, unless the parameters to the method are marked with the ref keyword, as in this example:
void MyRefMethod(ref string parm1)
{
Now, if I call this method the value of anything that I pass to that first parameter could be different after calling the method. To make sure that I realize that possibility, the compiler also requires that the calling code use the ref keywords. In this code, the test on the last line is not guaranteed to be true and, thanks to having to provide the ref keyword, I know that:
string PossiblyChanged;
PossiblyChanged = "Fred";
MyRefMethod(ref res);
if (PossiblyChanged == "Fred") ...
While a parameter marked with the ref keyword may or may not be changed, the out keyword is more definite: The out keyword indicates that code inside the method will always change the value in the parameter. If you mark a parameter as out and there is a path through your method that doesn't alter the value of the parameter then the compiler will generate an error.
In addition, with the out parameter, the compiler will refuse to compile your method if, inside your method, you attempt to use the out parameter without first setting its value. In other words, when calling a method with an out parameter, the calling code can set the value of the parameter before passing it to the method -- but it won't do a bit of good because the method has to override that value before it can use the parameter. Again, because I have to use the out parameter when calling the method, I know that:
string DefinitelyChanged;
MyRefMethod(out DefinitelyChanged);
if (DefinitelyChanged == "Fred") ...
That's it for now, I'm out.
Posted by Peter Vogel on 05/05/20160 comments
In the .NET Framework 4.0 or earlier, you have to set the culture for each thread individually. At the very least, this meant setting the CurrentThread object's CurrentCulture and CurrentUICulture properties. In the .NET Framework 4.5, you can do it in just two lines of code for every thread in your application, using the CultureInfo object.
The syntax is a little "un-obvious": You must first instantiate a CultureInfo object, passing a culture code. You then pass that object to a static method called DefaultThreadCurrentCulture, also on the CultureInfo object.
Typical code looks like this:
Dim ci As CultureInfo
ci = New CultureInfo("en-CA")
CultureInfo.DefaultThreadCurrentCulture = ci
which sets the culture code for all threads to English/Canadian.
Posted by Peter Vogel on 05/03/20160 comments
One of the best things about Solution Explorer is that I can right-click on a Project, pick "Open Folder in File Explorer" and, a second later, I'm in Windows Explorer, able to work with the files that make up the project. This also works with Solutions or, really, any folder displayed in Solution Explorer (for example, if you have Show All Files turned on, you can use this with the bin folder or obj folders).
Often, however, I'm not focused on the Project (or Solution) as a whole: I'm interested in one specific file -- usually, the one that I have open in my editor window. When that's the case, I can just right-click on the file's editor tab and select "Open Containing Folder." This not only opens the appropriate folder in Windows Explorer, it also selects and highlights the file I'm interested in.
Posted by Peter Vogel on 04/21/20160 comments
Visual Studio has lots of templates but you probably use only a few of them. Why not create your own area with all (and only) the templates you actually use?
It’s easy to do: First, shut down Visual Studio. Then, open Windows Explorer and surf to the folder that holds your templates. This folder can move around a lot. For Visual Studio 2015 Community Edition on my computer, it’s at C:\Users\<username>\Documents\Visual Studio 2015\Templates\ProjectTemplates. For Visual Studio 2012 and earlier, I’d recommend looking in the area of C:\Program Files (x86)\Microsoft Visual Studio<version>Common7\IDE. If you can’t find the folder, probably the simplest solution is just to do a search for the ProjectTemplates folder from Windows Explorer.
Once you’ve found the ProjectTemplates folder, add your own subfolder within it and copy the templates you want from the other subfolders into your new folder.
After you’re done with that, make sure your computer is plugged in, your battery charged, and open the Visual Studio command prompt. In the command prompt type:
devenv.com /installvstemplates
One caveat: For Visual Studio 2015, I also had to navigate down to Common7/IDE before entering the command. Now press Enter and wait.
Microsoft stresses that it’s critical that you let this command run to completion, which is why it’s a good idea to make sure you won’t run out of power part way through. When the command finishes (when the prompt reappears in the command window), open Visual Studio and go to your project list. You should find your new area with the templates you selected in the project templates list.
Posted by Peter Vogel on 04/07/20160 comments
When you're debugging, you probably know that you can use the Debug | Step Out menu choice to exit a method without having to step through all the code in the method. But, if you want to step out and back to some higher-level method, you can do that also by using the Call Stack.
If you're not displaying the Call Stack window when stopped at your breakpoint, go to the Debug menu and select Windows | Call Stack. When the window appears, right click on the method where you want to stop again and select "Run to cursor" to continue executing until you get back to that method.
The first time you use this technique is a bit of a pain because you probably don't have the Call Stack window open. After you've used it the first time, however, the window will be right there waiting for you the next time you need it.
Posted by Peter Vogel on 04/01/20160 comments
You have a method like this that returns a collection of premium Customer objects:
Public Function GetPremiumCustomers() As List(of Customer)
Dim db As New dbContextObject
Return From c In db.Customers
Where c.IsPremium = True
Select c
End Function
The problem is that other developers will want to use your method to further refine this query:
res = (From c in GetPremiumCustomers()
Where c.City = "Regina"
Select c).ToList()
If you're not careful the GetPremiumCustomers will retrieve every premium customer when the developer using your method only wants some of the premium customers (the ones in Regina). Retrieving more data than you'll ever want is a sure way to slow down your application. Wouldn't it be great if the LINQ query inside your method could be combined with the LINQ query using your method when the SQL statement is generated?
You can give .NET the opportunity to do exactly that -- to collapse both queries into a single SQL statement that retrieves only the premium customers from Regina -- if you just declare your GetPremiumCustomers method as returning the IQueryable interface. All you need to do is write your function's signature:
Public Function GetPremiumCustomers() As IQueryable(of Customer)
Return From c In db.Customers
Where c.IsPremium = True
Select c
to return a result of IQueryable.
Posted by Peter Vogel on 03/16/20160 comments
You have a GetCustomerById method in a factory object inside a repository that, when passed a CustomerId, returns a Customer object. Except, of course, sometimes there isn't a matching Customer object to return. What's the best way to handle this?
You have three options:
- Raise an exception.
- Return Nothing/null
- Return a "special object"
Raising an exception has performance implications because everything stops for tea when .NET processes an exception. Really, you should only raise an exception if you intend to stop processing … and that's not a decision that should be made by some method in some middle-tier object. Stopping the application is a decision that should be made by the application itself.
The second option isn't a bad one … except that quite a lot of code doesn't deal well with null references. By returning null/Nothing you're forcing the developer calling your method to wrap it in a Try…Catch block (there's those exceptions again) or test for null. And a null reference doesn't tell the developer much about what went wrong.
Your third option is really your best choice and it even has a name: The Special Case pattern. The only wrinkle is that your special object has to be compatible with the datatype that your method is returning (Customer, in this case). Your special object will, therefore, need to be some class that shares an interface with the objects that your method normally returns.
If, for example, your method returns a Customer object then your special object will need to be something that inherits from Customer -- a CustomerNotFound class, for example. The CustomerNotFound object should have all of its properties set to their default values.
Now code that calls your method can use the datatype of the special object:
Dim cust As Customer
cust = CustomerFactory.GetCustomerById("A123")
If TypeOf cust Is CustomerNotFound Then
to see what kind of error occurred.
Posted by Peter Vogel on 03/04/20160 comments
As programmers, we often talk about how it's better for components of an application to be isolated from each other. We recognize that, with our present programming tools, some level of coupling is unavoidable. We take it for granted, for example, that we have to use "signature coupling": To call a method we must know the method's name, the format of its parameter list and the data type of its return value.
But we also recognize that when we go beyond that level of coupling we start to create problems for ourselves. The primary problem is that, as components are more tightly coupled, changes in one component require changes in other components … and changes in those "other components" then require changes to still more components.
Where, I think, many developers don't realize that they've made their components too tightly coupled is in what's called "control coupling." Control coupling occurs when you pass a parameter to a method that controls the way the method behaves. The clue here is that inside a method you have an If statement (or some other conditional) that tests a parameter passed to the method and, based on that test, has the method do something different (other than, perhaps, throwing an exception because bad data was passed in the parameter).
Effectively, with control coupling, the code that calls a method is messing with the internal processing of that method. With this level of coupling any changes to how those control parameters are used (in either the method being called or in the calling code) are going to require changes to the other set of code.
The first step in reducing this level of coupling is to recognize that when you write code like this you're probably violating the separation of concerns principle: You have a method that does two things rather than doing one thing well. Your If statement is selecting between the two different things your method is doing. You're probably going to be better off to write two methods, each of which handles one piece of functionality.
There are two benefits here. First, all the versions of your method will now be much simpler. Simply eliminating an If statement cuts your method's complexity in half (after all, now there's only one path through the method to test). Second, when you want to change how things are done, you won't change any existing code. Instead, you'll write a new method that does the right thing and have your application call that method. By doing this, you avoid violating Vogel's first law of programming: Don't screw with working code!
If you feel that's going to make calling the right method hard to do, remember that you have options for simplifying that. Overloading will let you create multiple versions of a single method, each version of which is dedicated to handling a specific parameter list.
Moving code to classes derived from the same base class will let you hide different versions of the code behind the same signature (for example, the CreditCheck method does something different in PremiumCustomer than it does in DeadbeatCustomer). Any common code shared between the two versions can be put in the base class. You don't even need a base class: The Strategy and Role design patterns also allow you to put different implementations behind the same signature, as will effective use of interfaces.
If you value loose coupling, reducing control coupling might be your next step.
Posted by Peter Vogel on 02/26/20160 comments
When it comes to debugging problems with your code, a good Exception object is your most valuable tool. I've talked before about how why returning information about an exception using the InnerException object will let you find out what the real problem is without giving away secrets about your application.
I've also discussed how to ensure that your server-side errors aren't masked by the generic 500 "something's gone wrong" HTTP error. I've even gone as far as to suggest that it might be useful to create your own custom exception object.
Some people might conclude that my programs must throw a lot of errors but that's not true. My concern is simple: Knowing precisely what went wrong when your program blows up helps you figure out what the problem is. Furthermore, knowing what data exposed the problem is often critical to solving the problem. To help you out with that, the Exception object provides a dictionary where you can tuck away data about an error that programs processing the error can use -- it's the Exception object's Data property.
The following code adds an item to an Exception object's Data collection with a key of CustomerId and sets that key to a value. The code then throws an Exception of its own, tucking the original exception (with its additional information) into the InnerException property:
Try
...code that might throw an exception...
Catch ex As Exception
ex.Data.Add("CustomerId", custId)
Throw New Exception("Failure in processing Customer", ex)
End Try
Alternatively, you can create your own Exception object and add to its Data collection:
Try
...code that might throw an exception...
Catch ex As Exception
Dim myEx As New Exception("Failure in processing Customer", ex)
myEx.Data.Add("PersonId", pers.FirstName)
Throw myEx
End Try
The code that processes an Exception doesn't have to know precisely what's in the Data collection in order to report on it. Instead, you can just write out everything in the Data collection using code like this:
For Each key In ex.Data.Keys
Debug.Print(key & ": " & ex.Data(key))
Next
There are two things to avoid here. First, make sure that retrieving the information you're going to put in the Data collection won't itself trigger an exception (don't try to set a key to the property of a potentially null reference, for example). Second, don't add to the collection of any Exception object that you haven't just created because you might overwrite a Data value that was set elsewhere.
Posted by Peter Vogel on 02/23/20160 comments