Entity Framework: Soft Deletes Are Easy

What is soft delete?

When you work with data in your database you often need to delete records from the table. The standard and well known way to do that is just to execute DELETE query over this record (or force your ORM data mapper to do this for you).

DELETE FROM Companies WHERE CompanyId = 1

But there are many reasons you may want to “keep” your deleted records. For instance, if something has been removed accidentally by the user, or deletion was caused by the bug in your software. Sometimes backup won’t work for you, or restore data from backups can become a pain.

Imagine when you have IDENTITY(1,1) specified over CompanyId:

CompanyId int IDENTITY(1,1) NOT NULL

You accidentally removed this record and you want your company back with the same Id, because you already have urls like yourwebsite.blabla/company/1

You can’t perform

insert into Companies values (1, ...) 

easily and override identity column (MS SQL server will ask you to switch IDENTITY_INSERT to ON, can’t say a lot about other databases).

But the more serious reason comes into play when you have relationships between your entities (and foreign key constraints in your database).

Imagine that you have “Company – Newsletter” one-to-many relationship. Company can contain many newsletters, and newsletter belongs to one company. In this case when you delete a company, you need to delete all of the newsletters as well. You still can do this with database mechanisms like cascading deletion. But there are two reasons you don’t wanna do that:

1. Data loss risk is much higher, with one delete query you can delete multiple records.

2. You shift your business logic to the database engine. Now database decides how to delete your records, so you can’t cover your business logic with tests.

So for us it would be better to keep all of the records in database, but filtering them out on the way to our application. Soft delete is the technique when you add additional boolean field to your entity table (I usually call it IsDeleted). And when you want to delete something, you just set IsDeleted property to true. Our Company entity:

public class Company
{
	[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
	public long CompanyId { get; set; }
	public string Name { get; set; }
	public bool IsDeleted { get; set; }
}

 

Lame way to handle soft deletes

When you have additional property specified, you can now exclude deleted records from your query:

Or even you can write your own extension. But this approach has several disadvantages:

1. You must care about IsDeleted everywhere
2. Your code will soon become over-complicated
3. It’s very easy to forget about IsDeleted

So we need something more flexible and much easier. Ideally, we must be able to work with entities in our application like they are actually deleted. This would be perfect:

We don’t have any IsDeleted dependency and we don’t have to care about that every time we write a query or access mapped ICollection properties. But is it achievable? The answer is yes.

Entity Framework Code First and Soft Deletes

It’s easy to use soft deletes with Entity Framework if you know the trick. The trick is to tell model builder to take care about IsDeleted property for our entity.

The code above works like a filter between the database and our application. You don’t need to filter your entities by checking IsDeleted property every time. Filtering will work inside of Entity Framework.

Save It To Database, Jim

When you already have IsDeleted property, you can easily delete entity with marking IsDeleted as true, right?

Wrong! The code above won’t work. Because IsDeleted is not mapped now. Code won’t generate any exceptions, but IsDeleted property will be skipped while saving changes. So we need to handle the standard delete functionality somehow:

In order the above to work, we must extend our database context and override SaveChanges. Note that I also added DeletedAtUtc property – it’s always useful to know when something has been removed. You can also add DeletedBy in order to keep a reference to the user who has deleted particular entity.

Overriding SaveChanges

Overriding SaveChanges:

The code above will iterate through every entity marked as deleted and will SoftDelete it. Note that it’s marked as deleted by Entity Framework when we remove an item from the context. And here is self-explanatory SoftDelete implementation:

This method will execute sql query over each removed entity:

UPDATE Companies SET IsDeleted = 1 WHERE Id = 123

To make it versatile and compatible with any entity (not just Company) we need to know two additional properties:

1. Table name for the entity (Companies in our case)
2. Primary key name for the entity (Id in our case)

There are two functions inside of SoftDelete method for this purpose: GetTableName and GetPrimaryKeyName. I have defined them in separate file and marked class as partial. So be sure to make your context class partial in order things to work. Here is GetTableName and GetPrimaryKeyName with caching mechanism:

Conclusion

Soft deletes are easy when you know how to cook them. This article will help you to implement soft deletes for your application. I hope we’ll see soft deletes functionality in next versions of Entity Framework.

Installing Git for Windows: git + ungit

There are many ways and manuals, but here is my experience. I tried a lot of different versions of Git for Windows, but came up with optimal configuration.

1. Download Msysgit. Rule number one is to avoid Git with Cygwin — it works, but you’ll get headache with file permissions sooner or later.

2. During Msysgit install:

  • switch off Windows Explorer integration
  • don’t create Start Menu folder
  • pick “Use Git from the Windows command prompt” option (in the middle)
  • leave “Checkout Windows-style, commit Unix style line endings” as it is (upper option)

3. If you use Far Manager or you have cmd.exe window open, restart it. Installation has updated your PATH variable, you have to restart console applications in order new path variable to come into play.

4. Type

git --version

, it should display something like

git version 1.9.2.msysgit.0

Git is better with UI. Let’s install one. I found pretty cool and easy cross-platform Git UI called ungit. Ungit is operated by node.js, so we have to install node.js first.

5. Download and install node.js. Nothing fancy here, but remember node.js installation directory.

6. Restart your Far Manager or cmd.exe window again. Node.js will update your PATH variable again.

7. Try running

node -v

it should display

v0.10.22

8. If it doesn’t work, add C:\Program Files\nodejs or C:\Program Files (x86)\nodejs (depending on where you installed node.js) to your PATH manually. Go to step 6 to check if it works.

9. Type

npm install -g ungit

Mind -g key, it’s important. It will install ungit globally, not in your current directory.

10. Create a directory for your test project, for instance in C:\Projects\test and switch to this directory.

11. Just type ungit it will run browser window. Windows may also ask for some security permissions, just grant all.

12. You’re done with installing ungit, now you can click “Make ‘C:\Projects\test’ a repository”, just do this. You’ll see empty screen, it’s absolutely okay. You must do your first commit.

13. Press Ctrl + C in your console and you’ll see .git folder created in your test directory. It means that repository has bin initialized here. You could do that also with

git init .

command, but ungit did it for you.

14. To run ungit in background mode use the following command:

start ungit

 New copy of ungit will be terminated if instance is already running.

In the next topic I’ll explain how to link your git with github and bitbucket accounts.

jQuery: when always isn’t always

Found a funny thing about jQuery API. I had following piece of code:

$.getJSON('http://smart-ip.net/geoip-json?callback=?',
	function (data) {
		// ...
	})
.always(pickDefaultIfNothingSelected);

I was working on automatic timezone detection based on user’s location. And I used third-party service (smart-ip.net) to detect country and city by IP. What I wanted to do here is just to set default option if nothing is selected, or in case of any errors. jQuery API has nice feature for that: always method.

What you usually expect from this chunk of code is functionality similar to Java or C#:

try {
}
catch(...) {
}
finally { // this is what you expect from 'always'
}

Now stop reading and try to find a bug in the code above by yourself.

Give up? Here is the answer. Third party service has dead, and I accidentally found, that my code is not working as expected. pickDefaultIfNothingSelected is never called. always method stopped working. It’s a funny thing, because it is exactly what you expect from always – to be executed always. I learned that $.getJSON .always() method won’t execute on HTTP errors.

I tried to replace it with:

$.ajax({
	url: 'http://smart-ip.net/geoip-json?callback=?',
	timeout: 3000,
	dataType: 'json',
	success: function () { pickDefaultIfNothingSelected(); },
	error: function () { pickDefaultIfNothingSelected(); }
});

And… it just works as a charm!

Conclusion: don’t believe in always. Check your code for $.getJSON and get rid of it.

PS Btw, there is another third-party service you can use for city and country detection.

Hetzner: How To Install Windows on Linux (PoC)

Hetzner – ultra affordable european dedicated hosting. Prices starting from 49 EUR / month for a powerful dedicated server with 32 GB RAM, 2TB software raid hard drive. You don’t need to pay more if you pick Linux as your operating system. But get ready to pay 25 euros / month more for Windows.

But there is uncommon way to install Windows instead of existing Linux. Note that in this case I assume you have your own Windows license. You won’t pay 25 EUR/month and actually I believe with some effort you can boot from any .iso and install whatever you want. But in this post I’ll cover just Windows installation.

So, what do you need to install Windows on Hetzner?

1. Go to your control panel, your server, and ask for LARA support. Usually staff plugs LARA console within 30 minutes.

2. When you have LARA plugged to your server (btw, I know your LARA login – kunde, right?), go to Interfaces – Virtual Media from the top menu. You need Image on windows share dialog at the right.

3. Type the following settings:

Share host /IP : mirror.hetzner.de
Share name: windows
Image file with path: SW_DVD5_Win_Svr_Std_and_DataCtr_2012_64Bit_English_Core_MLF_X18-27588.iso

4. You will have media attached to your server. Just reboot it and you’ll be able to install Windows from attached media. I found that it takes more time to install from this type of media, but it works.

5. Profit!

Hetzner: How to install Linux virtual machine on your Windows and give it real IP address

I use Hetzner and keep my dedicated server there. I have Windows installed on my physical server (need that to run Microsoft SQL Server running – it’s always better to your SQL server installed outside VM). What I want to do is to run Linux guest OS inside of Windows host.

I have two real IP addresses. One for Windows and one for Linux. If you don’t have second IP – go and grab it for just 2 EUR/month. I use VMWare to keep my guest operating systems. So I will cover only this software in this post.

Installation of VMWare is pretty simple. Next step is to install Linux. Personally, I used Ubuntu 14.04 minimal iso for my installation. Install it as usual from VMWare UI with Ubuntu packages you want. When you finish, just ping something to make sure you can access internet.

Now interesting part comes into play. You have two IP addresses, you must assign one IP address to your Windows machine. And another one will be assigned inside guest OS (Linux). When you finished installing your Linux, VMWare automatically configures it to be located inside your internal network, without any real IP addresses. We must fix that.

In order to fix, do the following:

1. UPD 04-Oct-2014: you don’t need this step

2. Find out real MAC address of your real server network card. Hetzner routers allow packets sent only from real MAC. The easiest way to find your mac address is to type ipconfig /all | more (from Windows). You will need this address on the next steps.

3. In VMWare right click on your guest OS name and click “Settings”. Select “Network adapter” and make sure your settings are the same:

sample_settings2

4. Click Advanced and type your MAC address from step (2) here.

5. We finished with VMWare, it’s time to set up our Linux. Switch to root mode by typing sudo bash. I use Midnight Commander editor to edit files, if you don’t have one, just add it with apt-get install mc. When you press F4 for editing file you’ll be prompted to pick your favorite editor. I use mcedit.

6. Open /etc/network/interfaces and make sure it’s configured like this:

sample_settings3

Use your own address, netmask, and gateway! But you can use nameservers above, they are just OpenDns.

7. Shut down and start up your eth0 interface with commands: ifdown eth0, ifup eth0

8. It still won’t work 🙂 Just shutdown your Linux machine with shutdown command. Power off this machine in VMWare and power on it again. This step is required to assign MAC address from step (2) to your virtual network card.

9. Start your Linux. Try ping something. Try to ping your gateway. Try to ping your Windows Host OS. If it doesn’t work, type ifconfig and check if MAC address has been successfully assigned.

Good luck, and happy virtualizing!

 

Installing Ruby For Windows – The Right Way

It’s unbelievable. There are plenty of manuals available on the Internet, but there is no right one. Installing Ruby and Rails on Windows is pain, comparing to Linux and OS X. So in this topic I’ll cover it step by step. Hope it can help you to save some time.

How to install Ruby and Rails – the right way:

1. Install Ruby with Ruby Installer. Pick your version. I use the latest one (2.0 when I’m writing this post). Pick your operating system: 32 or 64 bit. In this guide I use x64 version of Ruby installed in C:\Ruby200-x64

2. Make sure you have updated PATH variable pointing to: “C:\Ruby200-x64\bin” (without quotes). Press Win+R, type cmd, then type irb. You must have irb in your path. Type ruby -v to show ruby version.  Note: if you use Far Commander or other commanders you might need to restart this application.

3. Ruby is installed, it’s time to install gems. Before you can install gems, you need to install Development Kit. Go to Ruby Installer Downloads page. Pick development kit for your version of Ruby and operating system. Unpack development kit to C:\RubyDevKit

4. Change directory to C:\RubyDevKit with your favorite file manager (mine is Far Commander) or via cmd, and type ruby dk.rb init

5. Open config.yml file and add the following line right after “—” (triple dash)  if it’s not there already:
– c:/Ruby200-x64 (don’t copy and paste, just type dash, space and then type your path)

6. Run ruby dk.rb install . Here is the sample output:
[INFO] Updating convenience notice gem override for ‘c:/Ruby200-x64’
[INFO] Installing ‘c:/Ruby200-x64/lib/ruby/site_ruby/devkit.rb’

7. Now you can install gems. Try installing hipchat gem: gem install hipchat . If everything’s fine, you’re almost done. Try gem install rails .

8. If you still have errors installing gems, try

gem update --system

9. Now you need to update your SSL certificates. You don’t have any SSL certificates at the moment, so there is a big change that some of your gems won’t work (if they access a server by https for instance, like hipchat). Now it’s time to install these certificates. Run this script to download cacert.pem. Make sure you have added SSL_CERT_FILE variable to your environment pointing to downloaded cacert.pem.

Now you’re done! Happy coding!

TODO: powershell script to automate this job.

Building a grid cell for iOS

When approached with building a tabular view of data on the iPad, my first thought was there has to be a grid control somewhere out there that does this. Having spent a good portion of my development time in C# lately, I’m used to seeing all of the feature rich libraries that are either out there on Github or that can be purchased from any of the control vendors. I did happen to find several solutions that would have worked, but my problem was just not that complex. The table’s needs are very simple. I need to be able to display rows of data that are laid out in a grid.

Here is how I accomplished that:

First thing was first, subclassing UITableViewCell

[gist https://gist.github.com/ro31337/cb2f258abea438ba7184]

Then in the implementation, I’m overriding drawRect:

[gist https://gist.github.com/ro31337/fae2cc512a560bfa8e37]

So what’s going on here, is I’m allowing the cell to keep track of the X positions where the line needs to be drawn. This is stored in the columns NSMutableArray. Then when the cell is being drawn, I’m iterating the columns and drawing a line that goes from the top of the cell down to the bottom.

And then in my Controller when the cell is being created, I call addColumn with the X coordinate that I want to draw the column at.

Like I said, my requirements were super light and this has worked out really well for me so far.