g | x | w | all
Bytes Lang Time Link
272C#140210T222159ZHand-E-F
108Ruby140208T033529Zdaniero
nan140208T002944ZAdam Spe

C#, 272 bytes

Not a great answer, but it works. If I understand Linq correctly, this opens the input file repeatedly, once for each line it writes to the output.

namespace System.Linq{
    class P{
        static void Main(string[]a)
        {
            var v=IO.File.ReadAllLines(a[0]).Select(y=>y.Split(',').ToList());
            var l=v.First();
            var s="\"\"";
            for(;;){
                IO.File.AppendAllText(a[1],string.Join(",",l)+"\n");
                l=v.FirstOrDefault(x=>x[2]==s);
                if(l==null)break;
                s=l[0];
            }
        }
    }
}

Input file:

"ID","Before","After","Value"
"1","3","5","Cat"
"2","5","","Apple"
"3","4","1","Dog"
"4","","3","Elephant"
"5","1","2","Banana"

Output file:

"ID","Before","After","Value"
"2","5","","Apple"
"5","1","2","Banana"
"1","3","5","Cat"
"3","4","1","Dog"
"4","","3","Elephant"

Ruby 109 108

Saved one whole character by using randomization instead of searching!

h,*t=[*$<]
t.shuffle!until t.each_cons(2).all?{|c|a,b=c.map{|y|y.lstrip.split /[,\s]+/}
a[1]==b[0]}
puts h,t

This only prints to stdout, so to save to a file use ruby csv.rb in.csv > out.csv.

$ cat test.csv 
ID,    Before,   After,   Value 
 1,         3,       5,    Cat
 2,         5,        ,    Apple
 3,         4,       1,    Dog
 4,          ,       3,    Elephant
 5,         1,       2,    Banana
$ ruby csv.rb test.csv 
ID,    Before,   After,   Value 
 2,         5,        ,    Apple
 5,         1,       2,    Banana
 1,         3,       5,    Cat
 3,         4,       1,    Dog
 4,          ,       3,    Elephant

Old version

puts gets,[*$<].permutation.find{|x|x.each_cons(2).all?{|c|a,b=c.map{|y|y.lstrip.split /[,\s]+/}
a[1]==b[0]}}

It simply finds the permutation of the lines where, for each line, the second column (Before) equals the first column (ID) of the next line.

VB.net (Non-Golfed)

Module Module3
  Public Sub Main(ParamArray args() As String)
    Dim items = CSVFileReader(args(0)).ToDictionary(Function(x) x(0))
    Dim Current = items.First(Function(kvp) kvp.Value(2) = "").Value
    Using out As New IO.StreamWriter(args(1), False) With {.AutoFlush=True }
      Do
        out.WriteLine("""{0}"",""{1}"",""{2}"",""{3}""", Current(0), Current(1), Current(2), Current(3))
        If Current(1) <> "" Then Current = items(Current(1))
      Loop Until Current(1) = ""
      out.WriteLine("""{0}"",""{1}"",""{2}"",""{3}""", Current(0), Current(1), Current(2), Current(3))
    End Using
  End Sub

  Public Iterator Function CSVFileReader(fn As String) As IEnumerable(Of String())
    Using t As New FileIO.TextFieldParser(fn) With {.Delimiters ={","},.HasFieldsEnclosedInQuotes = True, .TextFieldType=FileIO.FieldType.Delimited }
      While Not t.EndOfData
        Yield t.ReadFields
      End While
    End Using
  End Function
End Module

Probably a lot of room to golf that code.