Basic/Introduction Entity Framework Example/Tutorial - Code First approach


Back to learning
Created: 17/10/2019

Basic/Introduction Entity Framework Example/Tutorial - Code First approach

Tools:
Sql Server 2014
Visual Studio 2019
Entity Framework 6

Foreword
--------------
This is more like a manual where you can find specific solution to some problem you face, feel free to ask your questions in comments below, hope this helps you!

Setup
--------

1) Create the domain and Context
Create a Console application, then install using Nuget, Entity Framework, and finally add your DB connection string into your App.Config (can be also Web.Fonfig)

<connectionStrings>
    <add name="connEF" providerName="System.Data.SqlClient" connectionString="Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=Retail;Data Source=xxxxxx"/>
  </connectionStrings>

Provider name is very important

namespace ConsoleEntityF.Domain
{
    [Table("Products")]
    public class Product
    {
        public int id { get; set; }
        public string name { get; set; }
        public DateTime dateCreated { get; set; }
    }
}

Our context class, that derives from DBContext. (The main class that holds our business entities)
You can see, that we pass the name of our connection string as a parameter to a base class.

namespace ConsoleEntityF
{
    public class RetailContext : DbContext
    {
        public RetailContext():base("connEF")
        {
            // Turn off initializer
            //Database.SetInitializer<RetailContext>(null);
        }

        public DbSet<Product> productsLst { get; set; }
    }
}


Finally i created my Console application, with an addictional CRUD Class

--------------- ----------------------- ------------------------------ -------------------------- -------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleEntityF
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Begin trx");

            EFCrud ef = new EFCrud();
            /*foreach (Domain.Product p in ef.GetAllProducts())
            {
                Console.WriteLine(string.Format("{0}, {1}, {2}", p.id, p.name, p.dateCreated));
            }*/

            Domain.Product p = new Domain.Product();
            p.id = 1;
            p.name = "Entity Update 5";
            p.dateCreated = DateTime.Now;
            p.price = 150;
            
            ef.InsertProduct(p);

            Console.WriteLine("End trx");

            Console.ReadKey();
        }
    }

    public class EFCrud
    {
        public void InsertProduct(Domain.Product p)
        {
            using (RetailContext ctx = new RetailContext())
            {
                ctx.productsLst.Add(p);
                Console.WriteLine(ctx.Entry<Domain.Product>(p).State);
                ctx.SaveChanges();
            }
        }

        public List<Domain.Product> GetAllProducts()
        {
            List<Domain.Product> lst = null;

            using (RetailContext ctx = new RetailContext())
            {
                lst = ctx.productsLst.ToList();
            }

            return lst;
        }

        public void UpdateProduct(Domain.Product p)
        {
            using (RetailContext ctx = new RetailContext())
            {
                Domain.Product old = ctx.productsLst.SingleOrDefault(x=>x.id==p.id);
                old.name = p.name;
                Console.WriteLine(ctx.Entry<Domain.Product>(old).State);
                ctx.SaveChanges();
            }
        }
    }
}

--------------- ----------------------- ------------------------------ -------------------------- -------------------

2) Generate your Data Base from Your model with (migration commands)
First you need only once to enable "enable-migrations" in your Package Manager Console
Then you need to execute "add-migration", and specift any name
and finally execute "Update-Database -Verbose", to generate your DB.

This two commands "add-migration" and "Update-Database -Verbose" you will repeat every time you make a change to your model.


3) Just to test if everything works properly repeat the specified in the section 2 (migration commands), just add new property into your domain class, like this:

namespace ConsoleEntityF.Domain
{
    [Table("Products")]
    public class Product
    {
        public int id { get; set; }
        public string name { get; set; }
        public DateTime dateCreated { get; set; }
        public decimal price { get; set; }
    }
}

and execute this two commands "add-migration" and then "Update-Database -Verbose" you will repeat every time you make a change to your model.

And see if your table has been changed. New column price shoud be added


4) Production deployment

If you want to share domain changes with your coworkers then you simply chekcin your changes into a subversion system and your coworker get that changes. Then he can do the same as you, just update-database and localy he will have exactly the same as you.

But eventually you will need to deploy your changes to production, and in that server you dont have visual studio or something to run the commands. So basically you need to create a SQL script and just deploy that script into production. The command to run in your Package Management Console is the following: 

 update-database -Script -SourceMigration: 201910171454328_InitialCreate -TargetMigration: 201910172039453_xx

just search a little bit about this command "update-database -Script"
its very easy

Others:

Resetting system state (migrations)
When you have done many modifications to your model entities, you will probably have a lot of migrations files in your "Migrations" folder, and so, many registers in _MigrationHistory table in your database. What you can do in this case, is just delete history table and all the history cs files in your folder, and create a new one, so it will be your new InitialState. 
Eventually at the end you will insert your Initial record into History table manually, using "update-database -Script" comand.

Excelent manual how to reset your system state: https://weblog.west-wind.com/posts/2016/jan/13/resetting-entity-framework-migrations-to-a-clean-slate

Rollback migration:
Rollback to specific migration:
Update-Database -TargetMigration:"MigrationName"

Rollback all migrations:
Update-Database -TargetMigration:0

Relationship between classes, how to include subclasses, or use navigation properties:
You can use "Include" method and specify the name of the property
context.Customers.Include("products");

Or just include Entity namespace, and then specify the property:
using System.Data.Entity;

context.Customers.Include(c => c.products);

Column type:
If you want to specify specific datatype of your property that will be mapped to the DB you can do the following:
This will create "name" column as a Varchar(50) and not as a nvarchar, maby you want to use this column as a unique, this way you will be able to do it

        [Column(TypeName = "varchar")]
        [StringLength(50)]
        public string name { get; set; }