Introducing Index Attribute in Entity Framework Core
Tags: csharp, efcore, aspnetcore, microservices
Published: 2020-05-26 15:05:55

---
title: Introducing Index Attribute in Entity Framework Core
published: true
description: This is the story why I have made the Entity Framework Core Index Attribute while migrating my current monolith system.  
tags: csharp, efcore, aspnetcore, microservices
cover_image: https://res.cloudinary.com/practicaldev/image/fetch/s--a0j58u6j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6t58dccb0rftvgr8haeo.PNG
---
## The story of migration
I have developed some medium scale applications (medium scale = 20+ model/tables in a database) which is running smoothly on ASP.NET Web API and Entity Framework tech stack from 2016. I have been maintaining those projects perfectly fine.

But as the whole world is now crazy on MicroServices architecture, and the list of requirements of my clients are growing, so I thought, "Ok, let me migrate all of the old things to new and shiny boxes."

## The Extension

As my repository architecture was awesome, I thought it would be very smooth and minimum code change needed to migrate on EF Core. But the first hit I had was, there was no Index attribute in EF Core. Ok, it wasn't here in 2018, I knew, but in 2020? It should be introduced already. 
Since Index support is not here, and I am super lazy to write all of the plumbing code (ie. `HasIndex`, `HasName` for each property), I wrote a simple extension. 

[GitHub Snippet](https://github.com/foyzulkarim/BizBook.Common.Library/blob/151450b4c0f2b97323602adf403622e52555c40f/BizBook.Common.Library/Models/DbContextExtension.cs#L40)

```
public static ModelBuilder BuildIndex<T>(this ModelBuilder builder) where T : class
        {
            var propertyInfos = typeof(T).GetProperties().ToList().Where(x => x.GetCustomAttributes(typeof(IsIndex), false).Length > 0);
            foreach (var propertyInfo in propertyInfos)
            {
                //var propertyInfo = typeof(T).GetType().GetProperty("PhoneNumber");
                var parameterExpression = Expression.Parameter(typeof(T), "x");
                var memberExpression = Expression.PropertyOrField(parameterExpression, propertyInfo.Name);
                var lambda = Expression.Lambda<Func<T, object>>(memberExpression, parameterExpression);
                string indexName = $"IX_{propertyInfo.Name}";
                builder.Entity<T>().HasIndex(lambda).HasName(indexName);
            }

            return builder;
        }
```

# How do I use it?

### In DbContext
In my actual model project, in the DbContext's OnModelCreating method, I just call the model like below. 
[GitHub Link](https://github.com/foyzulkarim/BizBook.Common.Library.Consumers/blob/8f78bf58f067d9c749bc8cd71643974383ee1ac8/BizBook.Products/BizBook.Products.Api/Models/Db/ProductDbContext.cs#L27)
```
protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.BuildIndex<ProductGroup>();
            modelBuilder.BuildIndex<ProductCategory>();
            modelBuilder.BuildIndex<ProductDetail>();
            base.OnModelCreating(modelBuilder);
        }
```

### In POCO

And in the model class, I decorate the the properties with the `IsIndex` attribute, like below. 
[GitHub Snippet](https://github.com/foyzulkarim/BizBook.Common.Library.Consumers/blob/8f78bf58f067d9c749bc8cd71643974383ee1ac8/BizBook.Products/BizBook.Products.Api/Models/Entities/ProductGroup.cs#L11)

```
        [IsIndex]
        [Required]
        [Column(TypeName = "varchar(128)")]
        public string Name { get; set; }
```

If we add the migration, we should see Entity Framework Core actually understands the attribute now and translate it to the migration file. 

[GitHub Snippet](https://github.com/foyzulkarim/BizBook.Common.Library.Consumers/blob/8f78bf58f067d9c749bc8cd71643974383ee1ac8/BizBook.Products/BizBook.Products.Api/Migrations/20200522030316_Initial.cs#L182)

```
 migrationBuilder.CreateIndex(
                name: "IX_Name",
                table: "ProductGroups",
                column: "Name");
```

So, when I run `update-database` to apply the migration, I see the indexes are created into the table. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6t58dccb0rftvgr8haeo.PNG)


# Real case scenario

Just imagine, my current monolithic system is having these tables. And each of the table is having at least 10/15 indexes. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/j37lxnyjnoep5otsl9jt.PNG)

If I were not to write this index attribute, I would have gone crazy just to type the HasIndex and HasName codes. 😂🤣

## Future posts
I am converting the big monolith system into microservices architecture. The basic version of monolith system can be found in GitHub. Below are some repositories you might find interesting. 

[BizBook Server](https://github.com/foyzulkarim/bizbook-server)
[BizBook AngularJS 1.5 Client](https://github.com/foyzulkarim/bizbook-client)
[BizBook Server Core](https://github.com/foyzulkarim/bizbook-server-dotnet-core)

So, in the journey of splitting the monolith to MicroServices, I extracted all of the common codes into [BizBook.Common.Library](https://github.com/foyzulkarim/BizBook.Common.Library) repository. 

You can also install the package through 
https://www.nuget.org/packages/BizBook.Common.Library.EntityFrameworkCore

I will be very glad if you can give some feedback. 🙂
If you find these helpful, you can buy me a coffee. I love coffee. 

<a href="https://www.buymeacoffee.com/foyzul" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-red.png" alt="Buy Me A Coffee" style="height: 51px !important;width: 217px !important;" ></a>

#HappyCoding