Attach to Process

Thoughts and Notes on Software Development

As software developers, one of the problems we have to be mindful of, is our tendency to “reinvent the wheel”. By this I mean the tendency for developers to write a new application to solve a problem, that could have been solved by simply using existing applications/tools. When faced with the problem of importing all ObjectIds from a MongoDB collection into a SQL Server table, I thought I needed to write a new migration/utility app. Turns out I don't need to write any code at all, well except for the MongoDB query of course, but that's besides the point. Here is how I solved this problem using free tools available on the Internet.

Solution

First up is the MongoDB query that will get you all ObjectIds from a collection. I use the free Robo 3T app to query MongoDB.

db.getCollection('Collection').find({},{_id:1});

Robo 3T has a “view results in text mode” option that will display the results in JSON format. Select that and then run the query listed above. You will then be presented with results that will look similar to what I have below.

/* 1 */
{
    "_id" : ObjectId("5cba07dcca67bd08e8a6b3e2")
}

/* 2 */
{
    "_id" : ObjectId("5cba07b4ca67bc33705ded1d")
}

/* 3 */
{
    "_id" : ObjectId("5cba07baca67bc33705ded1e")
}

So now we have a list of ObjectIds from MongoDB. Imagine if you got back thousands of ObjectIds. It would be tempting at this point to say something like, hey I need to write a console app that can parse these results. I know I did. And I did write such an app, but eventually I realized I didn't need to. All I needed was Notepad++. Actually any text editor with a good enough “search and replace” feature will work.

After copying those results from Robo 3T into Notepad++, you can then use the “search and replace” functionality to transform the results into INSERT scripts that you can run in SQL Server.

So first thing you need to do is comment out all those brackets { and }. To do this, you simply search for { or } and replace the values with --{ or --}. Adding -- to the start of a line will comment it out in SQL Server. You can also opt to simply just delete all those brackets. SQL Server won't care if there are spaces between INSERT scripts. At this point your text file in Notepad++ will look similar to what I have below.

/* 1 */
--{
   "_id" : ObjectId("5cba07dcca67bd08e8a6b3e2")
--}

/* 2 */
--{
   "_id" : ObjectId("5cba07b4ca67bc33705ded1d")
--}

/* 3 */
--{
   "_id" : ObjectId("5cba07baca67bc33705ded1e")
--}

The second thing you need to do is to transform the lines with the ObjectId values in it, into SQL Server INSERT statements. To do this you go through two steps:

  1. Search for "_id" : ObjectId(" and replace the values with INSERT INTO [dbo].[MongoDbObjectIds] ([ObjectId]) VALUES ('. (This is assuming you have a MongoDbObjectIds table in SQL Server with an ObjectId column.)
  2. Search for ") and replace the values with ');. This will round out the INSERT statements. At this point, you should have valid INSERT statements that can be used in SQL Server. They should look similar to the ones I have below.
   /* 1 */
   --{
      INSERT INTO [dbo].[MongoDbObjectIds] ([ObjectId]) VALUES ('5cba07dcca67bd08e8a6b3e2');
   --}

   /* 2 */
   --{
      INSERT INTO [dbo].[MongoDbObjectIds] ([ObjectId]) VALUES ('5cba07b4ca67bc33705ded1d');
   --}

   /* 3 */
   --{
      INSERT INTO [dbo].[MongoDbObjectIds] ([ObjectId]) VALUES ('5cba07baca67bc33705ded1e');
   --}

All that needs to be done now is to copy the INSERT statements, run them in SQL Server Management Studio and you are done.

Now it must be noted that this approach to getting ObjectIds out of MongoDB and into SQL Server, is useful only if you are doing it once or twice. As soon as you have to repeat this process multiple times throughout the week or worse, throughout the day, then by all means write a migration/utility app to automate the process. It might take you longer to finish it, but the re-usability of said migration application will pay for itself in the future.

Hope you found this post helpful. Happy Friday to everyone!

Tags: #MongoDB #SqlServer #Scripts #Database

Discuss... or leave a comment below.

Have you ever had to do testing wherein you had to move your system date/time forward or back? If so, you will probably agree that one of the annoying things is remembering to reset the system date/time back to the current date/time. Most people will manually do this, which can be tiring when done multiple times during the day. If you are working in an office environment, then your workstation's system date/time can most likely be synced to a domain controller. Here is how you can easily do that using the command prompt in Windows.

Open up the command prompt and type in the command listed below:

net time /domain /set /y

You might have to open the command prompt in Administrator mode to get it to work.

Taking this a step further, what if you can automatically reset the system date/time on your workstation after a test finishes? I've had to do something similar since I've had to maintain some Coded UI tests, that can change the system date/time as part of their testing. So I wrote a utility method in C# that will reset the system date/time after a Coded UI test ends. This is called via the TestCleanup method that will run after a test ends.

[TestCleanup]
public void CleanUp()
{
    ResetLocalSystemTime();
}

private void ResetLocalSystemTime()
{
    using (Process netTime = new Process())
    {
        netTime.StartInfo.FileName = "NET.exe";
        netTime.StartInfo.Arguments = @"TIME /DOMAIN /SET /Y";
        netTime.StartInfo.UseShellExecute = false;
        netTime.StartInfo.CreateNoWindow = false;
        netTime.Start();

        Task.Delay(1000);
    }
}

Hope this helps some of the devs out there doing some testing. If you have a different way of doing this, do share them in the comments below or share them in a message.

Tags: #CSharp #DotNet #Tests

Discuss... or leave a comment below.

As the title states, you cannot use UPPERCASE letters when naming Containers in Azure Storage. I have no problem with this. My issue is that the exception message that is returned when running into this restriction, does not help me figure out what I did wrong.

This is the exception message I got: The remote server returned an error: (400) Bad Request.

Yeah, no help at all. Thankfully since I was writing the code, I could see where it was running into the exception. So I know it was an issue when trying to create a Container. It would have been a much bigger headache had I been trying to support a library that didn't have good exception logging or show the correct stacktrace.

I can somewhat understand why they did it this way though; it's most likely for security reasons that they are returning a very vague error. Either way, you have to know that there are a bunch of naming rules concerning how to name things in Azure Storage. For the official list from Microsoft, you can head over here.

Tags: #Azure

Discuss... or leave a comment below.

If you've ever needed to get a list of the base classes/types for an object in C#, this is one way of doing it. In my case, I had an object which was of the base class/type, but it was really a derived type.

Example: I had an object of type Animal, but it was really an instance of the Dog class, which is derived from the Animal base class.

The beauty of inheritance in object oriented programming is that the current instance of the object, can be an instance of the derived type, or the base type; it doesn't matter. As long as the code expects you to provide it an object of the base type, you can provide an instance of either one.

I needed to record the type hierarchy for that object when saving it to the database. So this utility method is what I came up with in short order. I am returning a list of strings in my example below, but there is nothing stopping you from returning an array of Types or whatever else you may need based on your scenario.

private List<string> GetTypeHierarchy()
{
    List<string> typeHierarchy = new List<string>();

    Type currentType = this.GetType();
    typeHierarchy.Add(currentType.Name);

    Type baseType = currentType.BaseType;
    while (baseType != null)
    {
        typeHierarchy.Add(baseType.Name);
        baseType = baseType.BaseType;
    }

    typeHierarchy.Reverse();
    return typeHierarchy;
}

I intentionally wrote this without recursion, because recursion hurts my head haha. There might be a better/cleaner way of doing this, if so, do share your solution with me.

#CSharp #DotNet

Discuss... or leave a comment below.

Recently I ran into an issue where I needed to exclude a property from getting serialized using Json.NET. The easy answer is to add a [JsonIgnore] attribute to the property. The problem with doing that is it will also ignore the same property during deserialization. So I needed a solution that allows me to ignore a property using serialization, but still set that property's value during deserialization. Thankfully I found a blog post from 2013 that explains exactly how to do that. I would have wasted more hours searching for an answer had I not found this solution right away.

There's a little known feature of Json.NET that lets you determine at runtime whether or not to serialize a particular object member: On the object you're serializing, you have to define a public method named ShouldSerialize{MemberName} returning a boolean value. – Marius Schulz

Visit Original Post: Conditionally Serializing Fields and Properties with Json.NET

It was only after I found Marius' blog post that I then found the documentation talking about conditional property serialization on the Newtonsoft website.

This is one of the rare instances where I didn't find the answer in StackOverflow. It makes me grateful for the developers who are still cranking out blog posts and sharing solutions to problems on their personal blogs/websites.

#Bookmarks #JsonDotNet #DotNet #Serialization

Discuss... or leave a comment below.

One of the best additions to SQL Server 2016 is native support for JSON. There a number of articles already covering how to query JSON in SQL Server, so I won't cover those. What particularly gives me headaches though is querying a JSON Array in SQL Server. Hopefully the scripts below can help someone else.

The SELECT script below can be used when you are working with a very basic JSON array that doesn't even have a Property for the array. In this example, we have an array of OrderIds.

DECLARE @OrderIdsAsJSON VARCHAR(MAX) = '["1", "2", "3"]';

SELECT [value] AS OrderId
FROM OPENJSON(@OrderIdsAsJSON)
WITH
(
       [value] BIGINT '$'
);

The second SELECT script below can be used when you are working with a JSON array that does have a Property defined for the array. In this example, we have an array of OrderIds with a defined OrderId property.

DECLARE @OrderIdsAsJSON VARCHAR(MAX) = '{"OrderId":["4", "5", "6"]}';

SELECT [value] AS OrderId
FROM OPENJSON(@OrderIdsAsJSON, '$.OrderId')
WITH
(
       [value] BIGINT '$'
);

Update: 2019-07-17

Adding another example for a JSON array that came from an Int list in C#. This is how you could query it in SQL Server.

DECLARE @OrderIds VARCHAR(MAX) = '{"$type":"System.Int64[], mscorlib","$values":[4, 5, 7, 999]}';

SELECT [value] AS OrderId
FROM OPENJSON(@OrderIds, '$."$values"');

#SqlServer #Scripts #Database #JSON

Discuss... or leave a comment below.

Out of the 5 SOLID principles, the Open/Closed principle was the hardest one for me to grasp. This post from Code Maze explains it really well and the code examples were very helpful. This was a good read.

Link: Open and Closed Principle

Rather than writing my own post about it, I thought I would share this one instead. After all, as programmers we should avoid reinventing the wheel as much as possible. This is also my first post in a new “Bookmarks” category that I've added to this website. The plan is to use that new post category to share interesting articles that I've found online.

#Bookmarks #SolidPrinciples #CSharp

Discuss... or leave a comment below.

Ever since upgrading to Visual Studio 2017, I was always annoyed that it no longer defaulted to opening the Output window whenever I start building the solution. If I remember correctly, opening the Output window or making it visible was the default behavior in Visual Studio 2013 and 2015. So with VS 2017 I've always had to manually open the Output window during or after a build to see the output summary. Turns out the fix for this is a very simple setting in Visual Studio (duh). This saves me a good number of mouse clicks in a day :)

Output Window Setting in Visual Studio

Reference: How to keep output window always open in Visual Studio 2017

#VisualStudio

Discuss... or leave a comment below.

I'm putting this TRY CATCH template on here in case other people might find it helpful. This is what I usually use when wrapping SQL Scripts in a stored procedure. Normally I would have go to Microsoft Docs to get the syntax for using TRY CATCH and RAISERROR. Having a template that I know works and is ready to go is just easier.

BEGIN TRY
   BEGIN TRAN

	-- Add your scripts in here
	
   COMMIT TRAN
END TRY  
BEGIN CATCH  
	WHILE (@@TRANCOUNT > 0)
	BEGIN
		ROLLBACK TRAN;
	END

	DECLARE @ErrorMessage NVARCHAR(4000);  
	DECLARE @ErrorSeverity INT;  
	DECLARE @ErrorState INT;  

	SELECT   
		@ErrorMessage = ERROR_MESSAGE(),  
		@ErrorSeverity = ERROR_SEVERITY(),  
		@ErrorState = ERROR_STATE();  

	RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);  
END CATCH;

#SqlServer #Scripts #Database

Discuss... or leave a comment below.

The scripts below will help you find a table in a SQL Server database based on a given “table name” filter. This is helpful if you are not familiar with a rather large database and didn't want to waste time looking for a table manually. In my case, I usually use these scripts to check for an existing table in a database, before I create a new one.

Most of the time when working with a large database, the table that you think you need to add, was already created by someone else. Oftentimes it is named differently than what you would have named it, but the contents and use of the table would have been the same. So it pays to double check before creating an already existing table.

SELECT *
FROM SYS.tables
WHERE NAME LIKE '%tableName%'

/* The script below will give you a result in the "schema.tablename" format, which can help you quickly locate the table. */
SELECT (SELECT [Name] FROM SYS.schemas AS S WHERE S.schema_id = T.schema_id) + '.' +  T.Name AS 'TableName'
FROM SYS.tables AS T
WHERE NAME LIKE '%tableName%'

#SqlServer #Scripts #Database

Discuss... or leave a comment below.

Enter your email to subscribe to updates.