0

In storing events into an event management system, I am also storing a history of the changes. Because the project specifies the use of MySql, and MySql triggers leave something to be desired, I am using actual code to detect changes. I have the following line of code to see if the support notes field changed, and add a history record accordingly:

    ....
    if (!String.Equals(OldEventInfo.supportNotes, NewEventInfo.supportNotes))
    {  ChangesMade.Add(new EventHistoryDataItem("support notes", OldEventInfo.supportNotes, NewEventInfo.supportNotes)); }
    ....
    EventsDataset eds = new EventsDataset();
    EventsDatasetTableAdapters.eventhistoryTableAdapter ehta = new EventsDatasetTableAdapters.eventhistoryTableAdapter();
    EventsDatasetTableAdapters.eventhistorydataTableAdapter ehdta = new EventsDatasetTableAdapters.eventhistorydataTableAdapter();
    Int64 HistoryId = Convert.ToInt64(ehta.InsertQuery(NewEventInfo.id.Value, DateTime.Now, UserId));

    eds.eventhistorydata.Clear();
    foreach (EventHistoryDataItem thisChange in ChangesMade)
    {
        EventsDataset.eventhistorydataRow newRow = (EventsDataset.eventhistorydataRow)eds.eventhistorydata.NewRow();
        newRow.eventHistoryId = HistoryId;
        newRow.field = thisChange.Field;
        newRow.oldValue = thisChange.OldValue;
        newRow.newValue = thisChange.NewValue;
        eds.eventhistorydata.AddeventhistorydataRow(newRow);
    }
    ehdta.Update(eds.eventhistorydata);

The problem is that I am getting history records for "support notes" with identical values in the before and after. I've looked at other questions on SO about string.equals generating false returns, and I have checked to make sure that the before and after strings were identical, and they are. There are no extra spaces or carriage returns or newlines. They are binary identical.

So, what gives? How is a record ending up in my history that says the value has changed from A to B, but with A and B being identical?

  • I realize you said that there were no spaces or carriage returns. But spaces and carriage returns are not the only characters which cannot be rendered. There are many more characters which the editors cannot render. One way to confirm that there are no extra characters would be to include a test for length: `if( OldEventInfo.supportNotes.Length != NewEventInfo.supportNotes.Length && !String.Equals(OldEventInfo.supportNotes, NewEventInfo.supportNotes)) { ... }` – Akhilesh Apr 07 '17 at 19:00
  • If they are binary identical, then their GetHashCode() should return the same value. If not, then they are not equal for whatever reason (like a difference in line endings or something along those lines). – Stephen P. Apr 07 '17 at 19:35
  • @StephenPorter - as it turns out, you are right, and it means that I lied. I went back and looked at this more carefully, and indeed the strings were different. Somewhere between the data going into MySql on a Unix server, and coming back, the Windows new-lines (carriage-return + line-feed - 0D0A) got turned into Unix new-lines (line-feed - 0A). And that was causing the strings to test not equal. –  Apr 10 '17 at 14:11
  • I'll probably delete this question in a little while. It turns out to be a duplicate of http://stackoverflow.com/q/25999031/4843530 –  Apr 10 '17 at 16:33
  • @AgapwIesu Good deal, glad you figured it out :) I struggled with this when I started working with .NET Core since I was developing in Windows, Dockerizing my app, and deploying to Linux servers. You run into line-ending and path issues haha. – Stephen P. Apr 10 '17 at 17:00

2 Answers2

0

It's because the string encoding is different and they strings are not equal, although they contain the same characters.

If you want to compare the two strings and they are from different sources, and you're not worried about the encoding, then compare them using the string.Normalize() method and it will work.

Michael Puckett II
  • 6,586
  • 5
  • 26
  • 46
  • Michael, do you know what string.Normalize does to platform specific implementations of New-Line? I have googled around and founds lots of articles on Unicode normalization, but nothing that tells me what happens with New-Lines. –  Apr 10 '17 at 16:17
  • Not really. You could mock up a quick console app, parse different versions of text into various binary encodings and test it. I'm curious... – Michael Puckett II Apr 10 '17 at 19:29
  • Good suggestion. Should have thought of it myself. I did such a mockup and Normalize leaves the carriage returns and line feeds untouched. Both carriage return and line feed exist in UTF-16 which is what c# strings use so I guess it considers both characters to be "normal" unicode. But I am not sure I am really understanding the concept of Unicode normalization. Anyway, thanks for helping me learn about this. I bet it will come in handy. –  Apr 10 '17 at 21:41
0

So the strings really were different. A careful binary comparison showed that there was a carriage return in one version of the string and not in the other. I had to pull the data straight out of the database to compare them...

select hex(OldValue), hex(NewValue) from EventHistoryData where Id = 39645;

which revealed that where there was supposed to be a new-line, one version of the string had a Windows implementation of new-line (CarriageReturn + LineFeed = \r\n = x0D0A) and the other had a Unix implementation of the new-line (LifeFeed = \n = x0A). Somewhere between my Windows IIS machine, and the MySql server on a Unix machine, the string's new-lines were getting converted to Unix implementation.

The simplest solution was to change the comparison to ignore Carriage Returns. Since the Windows NewLine is \r\n and the Unix and Mac newlines are \n, the simplest thing to do in comparing the strings was to remove the \r, turning all newlines into the Unix version. So

if (!String.Equals(OldEventInfo.supportNotes, NewEventInfo.supportNotes))

becomes

if (!String.Equals(OldEventInfo.supportNotes.Replace("\r",""), NewEventInfo.supportNotes.Replace("\r","")))