EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

47
Tutorial : EF Code First- Design Pattern Part 0 – Introduction: Our main goal is to develop a MVC website for a hypermarket using .NET framework and following this architecture: Part 1 - Setting up a solution: Create these projects in one solution named “MyFinance” “MyFinance.Domain”, “ MyFinance.Service”, “MyFinance.Data” ( 3 Class Library Project) MyFinance.Web (ASP.NET Web Application (mvc)) Add the references following this schemas. Web Mvc (MyFiance.Web) DAL : Data Access Layer(MyFinance.D ata) BLL : Business Logic Layer(MyFinance.S ervice) Entities Layer(MyFinance.Domain) Back- Office Front- Office DataBase User

Transcript of EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

Page 1: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

Tutorial : EF Code First- Design Pattern

Part 0 – Introduction:Our main goal is to develop a MVC website for a hypermarket using .NET framework and following this architecture:

Part 1 - Setting up a solution:Create these projects in one solution named “MyFinance”

“MyFinance.Domain”, “ MyFinance.Service”, “MyFinance.Data” ( 3 Class Library Project)

MyFinance.Web (ASP.NET Web Application (mvc))

Add the references following this schemas.

Reference

MyFinance.Domain

MyFinance.Service

MyFinance.DataMyFinance.Web

User

DataBase

Front-OfficeBack-Office

Entities Layer(MyFinance.Domain)

BLL : Business Logic Layer(MyFinance.Service)

DAL : Data Access Layer(MyFinance.Data)

Web Mvc

(MyFiance.Web)

Page 2: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

To add a reference follow these steps:

1. Right click on project that needs the reference2. Click Add3. Click Reference

4. In the Reference Manager Message box, check referenced projects

5. Click OK

Page 3: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

Part 2 – Entities and Context Implementation:Step 1 :

In the “MyFinance.Domain”, you should create a new folder named “Entities” that includes all the classes of the following classes’ diagram, don’t forget navigation properties.

The following code expose the different entities:

public class Category { public int CategoryId { get; set; } public string Name { get; set; } //navigation properties virtual public ICollection<Product> Products { get; set; } }

public class Provider { public int Id { get; set; } public string UserName { get; set; } public string Password { get; set; } public string ConfirmPassword { get; set; } public string Email { get; set; } public bool IsApproved { get; set; } public DateTime? DateCreated { get; set; } // ? nullable //navigation properties virtual public ICollection<Product> Products { get; set; } }

public class Product { public int ProductId { get; set; } public string Name { get; set; }

public string Description { get; set; } public double Price { get; set; } public int Quantity { get; set; } public DateTime DateProd { get; set; } //foreign Key properties public int? CategoryId { get; set; }

Page 4: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

//navigation properties public virtual Category Category { get; set; } public virtual ICollection<Provider> Providers { get; set; } }

public class Biological : Product { public string Herbs { get; set; } }

public class Chemical : Product { public string LabName { get; set; } public string City { get; set; } public string StreetAddress { get; set; } }

We've made the navigation properties virtual so that we get lazy loading.DateTime? Type is the nullable DateTimeWe used ICollection interface so we can use later any collection implementation.

Step 2 : Entity Framework Installation

Now, let’s move to “MyFinance.Data” project and add a reference to the Entity-Framework. So let’s open Manage NuGet package.

We need this reference so we can implement the context.

Do the same for “MyFinance.Web” project. Because entity framework won’t be deployed unless it’s referenced by the web project

We install the Entity Framework package

Page 5: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

Step 3 : Context Implémentation

A Context is a class inherits DbContext, and manage entities and database.

Add a new Context by following these steps:1. Create a class “MyFinanceContext” in “MyFinance.Data” project2. Add an inheritance from DbContext3. Add a default constructor that calls the parent one, and give it the named connection

string “DefaultConnection” that exists in the web.Config file in “MyFinance.web” project

4. Add sets (Collection for entities management)5. Add necessary using.

using MyFinance.Domain.Entities;using System.Data.Entity;

public class MyFinanceContext : DbContext { public MyFinanceContext() : base("Name=DefaultConnection") { } public DbSet<Category> Categories { get; set; } public DbSet<Provider> Providers { get; set; } public DbSet<Product> Products { get; set; } }

Step 4 : Scaffold a Controller

1. In “MyFinance.Web” Project add a reference to “MyFinance.Data” project (Context)2. Build the solution3. Right click on “Controllers” folder in the “MyFinance.Web” Project4. click “Add”5. click “controller” 6. in the message box choose : “MVC5 Controller with views, using entity framework”7. Fill the message box like this :

Web.config

Page 6: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

8. Click Add9. Explore the generated Controller and Views

Step 5 : Run and enjoy

Follow these steps:

1. Right click the “MyFinance.Web” project2. Click “Set as start-up project”

3. Click the button 4. Add “/products” to the url and visit the page Ex : “http://localhost:{your port}/products”5. Insert some data

Step 6 explore database

Select App_Data folder in “MyFinance.Web” and click on show all files icon

Open App_Data folder and double click on the mdf File

By default, Entity framework code first uses Table Per Hierarchy (TPH) method to handle inheritance when creating tables from entities. in TPH, All Data in the hierarchy will be saved in a single database table and it uses a Discriminator column to identify which record belongs to which sub type. The value of this column will be the name of the subtype.

Page 7: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

Part 3 – Update the model:Step 1 (Optional) : -Let’s try to add a property public string Image { get; set; } to the entity Product.

1. Run the application. Try to list products. What happen?

The application throws this exception:

2. Let’s add another class MyFinanceContextInitialize in the same file of the Context.

3. Override the Seed method inherited from the base class.

This method serves to seed the database in case on dropping and creating the database, so we can seed some data for test instead of adding data manually in the database each time the database is created.

public class MyFinanceContextInitializer : DropCreateDatabaseIfModelChanges<MyFinanceContext> { protected override void Seed(MyFinanceContext context) { var listCategories = new List<Category>{ new Category{Name="Medicament" }, new Category{Name="Vetement" }, new Category{Name="Meuble" }, };

context.Categories.AddRange(listCategories); context.SaveChanges(); } }

4. In order to set the initializer we have to add this code to the constructor of the class MyFinanceContext.

Database.SetInitializer<MyFinanceContext>(new MyFinanceContextInitializer());

-That exception is thrown because the model changed and the the Entity Framework Code First doesn’t know how it will behave. Therefore we have to tell the framework how it must behave.

This class inherit from DropCreateDatabaseIfModelChanges<MyFinanceContext>, which give the Entity Framework the strategy of initializing the application. In other word, this class informs the Entity Framework to drop and create the database if the model changes. We can replace this class by DropCreateDatabaseAlways or CreateDatabaseIfNotExists.

Page 8: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

5. In “MyFinance.Web” project, delete the controller “ProductsController” and the “Products” folder under the “Views” Folder and scaffold “ProductsController”. (same steps as Part2, Step4) to refresh the views with the new added property

6. Go to the server explorer panel, right click on your database and close connection. This Step is necessary to close all connection to the database, you delete the database in the SQL Server Object Explorer or Restart the visual studio

7. Run the application another time and check the database

Step 2 : -

Assuming that we are using a production environment and we have important data. Then we are not allowed to lose this data. In this case the initialisation strategy doesn't seem to be a good choice. So let’s try something else, Migration !!!! Let’s do it.

1. The first step: we have to enable the Migration: Open the Package Manager Console the choose the project “MyFinance.Data” which contains the class Context. Then execute this command Enable-Migrations

Entity Framework Code First generate a new folder “Migration” which contains two classes xxx_InitialCreate and Configuration. -The first class contains an Up () method that contains instructions to create the table with its original definition, and another method Down () to delete the table.-The second class define the behavior of the migration for DbContext used. This is where you can specify the data to insert, enter the providers of other databases …

2. The second step: we will change the name of the property public string Image { get; set; } to public string ImageName { get; set; }.

3. Execute the command Add-Migration ModifyNameImage in the Package Manager Console.4. The Add-migration command checks for changes since your last migration and scaffold a new

migration with any changes found. We can give a name for our migration, in this case, we call migration "ModifyNameImage".

5. Go to the “Configuration” class in “Migrations” folder and add the following code in the seed method of the migration :

context.Categories.AddOrUpdate( p => p.Name, //Uniqueness property new Category { Name = "Medicament" }, new Category { Name = "Vetement" }, new Category { Name = "Meuble" } ); context.SaveChanges();

6. Execute the command Update-Database -TargetMigration:"ModifyNameImage" in the Package Manager Console. This command will apply any pending migration to the database and then check the database.

Page 9: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

Part 4 – Complex Type:Step 1 : Let’s add a Complex Type “Address” in “entities” folder in “MyFinance.Domain” project

public class Address { public string StreetAddress { get; set; } public string City { get; set; }

}

To create a new Complex Type we have to follow those rules otherwise we have to configure a complex type using either the data annotations or the fluent API.

Step 2 : Let’s update “Chemical” entity with the complex type as the following :

public class Chemical : Product { public string LabName { get; set; } public Address LabAddress { get; set; } }

Part 5 – Configuration using annotations:Step 1 : Add a reference to “System.ComponentModel.DataAnnotions” assembly to the “MyFinance.Model” project

Page 10: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

Step 2 : Now , we will add different data annotations to configure those entities.

● In class Product : properties should be configured as the following :○ the property Name should be

■ required■ The user input string have the length 25 (max)■ The property have length 50 (max)■ An error message will be displayed if the rules are not respected.

○ The property Description should be■ Multiline

○ The property Price should be■ Currency

○ The property Quantity should be■ Positive integer

○ The property DateProd should be■ Displayed as “Production Date”■ Valid Date

○ The property CategoryId should be■ The foreign Key property to the Category entity.

public class Product { public int ProductId { get; set; } [DataType(DataType.MultilineText)] public string Description { get; set; }

[Required(ErrorMessage = "Name Required")] [StringLength(25, ErrorMessage = "Must be less than 25 characters")] [MaxLength(50)] public string Name { get; set; } [Range(0,double.MaxValue)] [DataType(DataType.Currency)] public double Price { get; set; } [Range(0, int.MaxValue)] public int Quantity { get; set; } [DataType(DataType.ImageUrl),Display(Name = "Image")] public string ImageName { get; set; } [Display(Name = "Production Date")] [DataType(DataType.DateTime)] public DateTime DateProd { get; set; }

//foreign Key properties public int? CategoryId { get; set; }

//navigation properties [ForeignKey("CategoryId ")] //useless in this case public virtual Category Category { get; set; } public virtual ICollection<Provider> Providers { get; set; }

}

Page 11: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

MaxLength is used for the Entity Framework to decide how large to make a string value field when it creates the database.StringLength is a data annotation that will be used for validation of user input.DataType : is used to specify a specific type : email, currency, card number …Display is used to change the displayed name of the propertyRange is used to limit valid inputs between min and max values. Foreignkey : To configure the foreign key

● In class Provider : properties should be configured as the following :○ the property Id should be

■ Key (Id is already a primary key By Convention )○ The property Password should be

■ Password (hidden characters in the input)■ Minimum length 8 characters■ Required

○ The property ConfirmPassword should be■ Required■ Not mapped in the database■ Password■ Same value as “Password” property

○ The property Email should be■ Email■ Required

public class Provider { [Key] // optional ! public int Id { get; set; } public string UserName { get; set; }

[Required(ErrorMessage = "Password is required")] [DataType(DataType.Password)] [MinLength(8)] public string Password { get; set; }

[NotMapped] [Required(ErrorMessage = "Confirm Password is required")] [DataType(DataType.Password)] [Compare("Password")] public string ConfirmPassword { get; set; }

[Required,EmailAddress] public string Email { get; set; }

public bool IsApproved { get; set; }

public DateTime? DateCreated { get; set; }

virtual public List<Product> Products { get; set; } }

Key Define the Key column in the database..NotMapped : no column would be generated in the database

Page 12: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

Comapre : compare two propertiesMinLength the opposite of MaxLength

Step 3 : Let’s Test

1. Update the database using migration 2. Delete « ProductsController » and products folder under Views folder3. scaffold a new « ProductsController » 4. scaffold « ProvidersController »5. Run and test

Part 6 – Configuration using fluent API:Note that the data annotations and the fluent API configuration could coexist.

Step 1 : Create new Folder named “Configurations” in “MyFinance.Data” project

Step 2 : Add CategoryConfiguration classes in the “Configurations” folder

public class CategoryConfiguration : EntityTypeConfiguration<Category>{

public CategoryConfiguration() {

ToTable("MyCategories");HasKey(c => c.CategoryId);

Property(c => c.Name).HasMaxLength(50).IsRequired(); }

}

-This class inherit from the generic class EntityTypeConfiguration , defined in « System.Data.Entity.ModelConfiguration », then we pass the type that we want to configure-In fact, Following the convention Entity Framework names the table created in the database with the name of the entity in plural. In this case the table generated will be named Categories. Therefore, when we want to change the name of the table we use the method ToTable(“MyCategories”).-We will apply some rules on the Name and the Description proprieties

Step 3 : Add ProductConfiguration classes in the “Configurations” folder : This step contains 3 main parts. The first part refers to the many-to-many association between products and providers, the second part configure the inheritance, the third part configure the one-to-many association between the Product and the Category.

public class ProductConfiguration : EntityTypeConfiguration<Product>{

public ProductConfiguration() { //properties configuration Property(e => e.Description).HasMaxLength(200).IsOptional();

//Many to Many configuration HasMany(p => p.Providers) .WithMany(v => v.Products)

Page 13: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

.Map(m => { m.ToTable("Providings"); //Table d'association m.MapLeftKey("Product"); m.MapRightKey("Provider"); });

//Inheritance Map<Biological>(c => { c.Requires("IsBiological").HasValue(1); //isBiological is the descreminator }); Map<Chemical>(c => { c.Requires("IsBiological").HasValue(0); });

//One To Many HasOptional(p => p.Category) // 0,1..* //if you need 1..* use HasRequired() .WithMany(c => c.Products) .HasForeignKey(p => p.CategoryId) .WillCascadeOnDelete(false); } }

The Many to many part configure the association between the Product class and The Provider class

Those classes have a many to many association. Entity Framework uses the convention to create an association table following this pattern. The name of the table will be the name of the first entity concatenated with the name of the second one. This table will contain two columns, those names will follow the next pattern: [The_name_of_the_navigation_propriety] [The_name_of_the_primary_Key]. This example explains better.In this case we want to alter the name of the association table as well as the names of the columns.

The inheritance part customizes the TPH inheritance:

Indeed Entity Framework create a flag column named Discriminator, so we want to change the name of the column to IsBiological. This column will contain the value 1 in the case of adding a Biological object. Otherwise it will contain the value 0.

The final part customizes the one-to-many association between the Product class and the Category class.

The Product can belong to a Category, which explains the optional relationship. In the HasOptional method, we pass the navigation propriety Category of the Product Class. The method WithMany specifies that the Category contains many Products. As well as the other method, we pass the navigation navigation property Products of the Category class.

We also want to disable the Cascade On Delete to conserve products after deleting an associated category. For this aim the foreign key “CategoryId” should be nullable

Step 4 :Finally we configure the complex type Address by creating this class:

Page 14: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

public class AddressConfiguration : ComplexTypeConfiguration<Address> { public AddressConfiguration() { Property(p => p.City).IsRequired(); Property(p => p.StreetAddress).HasMaxLength(50) .IsOptional(); } }

Step 5 : Update the Context to apply these configurations so, in the “MyFinanceContext” class override the “OnModelCreating” method like this :

protected override void OnModelCreating(DbModelBuilder modelBuilder) { //If you want to remove all Convetions and work only with configuration : // modelBuilder.Conventions.Remove<IncludeMetadataConvention>(); modelBuilder.Configurations.Add(new CategoryConfiguration()); modelBuilder.Configurations.Add(new ProductConfiguration()); modelBuilder.Configurations.Add(new AddressConfiguration()); }

Step 6 : Update the database by migration and explore it to see what the configurations have done.

Part 7 – Design Patterns:Step 1 : Add a new folder in “MyFinance.Data” project called “Infrastructure”

Step 2 : We will implement the Disposable pattern, but first we should understand why we will use this pattern.

In fact there are two types of resources in the Framework .Net:o Managed resources are resources that the garbage collector can be dispose when

there the reference is broken in the memory.o Unmanaged resources that are all that the garbage collector can not handle,

example: open files, database connections ...

How can we free up memory if any unmanaged resources remain? Solution: Dispose pattern

This is a design pattern that is used to clean unmanaged resources.

To provide explicit control, implement the Dispose method provided by the IDisposable interface. The consumer of the object should call this method when it has finished using the object.

Note that you must provide implicit cleanup using the Finalize () method, even when you provide explicit control with Dispose. Finalize () provides a backup to prevent a definitive resource drain if the programmer does not call Dispose.

Add a class Disposable which inherit from the IDisposable interface in the “Infrastructure” folder.

Page 15: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

public class Disposable : IDisposable { // Track whether Dispose has been called. private bool isDisposed; // Use C# destructor syntax for finalization code. // This destructor will run only if the Dispose method // does not get called. // It gives your base class the opportunity to finalize. // Do not provide destructors in types derived from this class.

~Disposable() { // Do not re-create Dispose clean-up code here. // Calling Dispose(false) is optimal in terms of // readability and maintainability.

Dispose(false); }

public void Dispose() { Dispose(true); // This object will be cleaned up by the Dispose method. // Therefore, you should call GC.SupressFinalize to // take this object off the finalization queue // and prevent finalization code for this object // from executing a second time. GC.SuppressFinalize(this); } // Dispose(bool disposing) executes in two distinct scenarios. // If disposing equals true, the method has been called directly // or indirectly by a user's code. Managed and unmanaged resources // can be disposed. // If disposing equals false, the method has been called by the // runtime from inside the finalizer and you should not reference // other objects. Only unmanaged resources can be disposed. private void Dispose(bool disposing) { // Check to see if Dispose has already been called. if (!isDisposed && disposing) { DisposeCore(); } isDisposed = true; }

protected virtual void DisposeCore() { } }

Step 3 : Then we will add an interface IDatabaseFactory which inherit from the interface IDisposable in the “Infrastructure” folder.

public interface IDatabaseFactory : IDisposable{ MyFinanceContext DataContext { get; }}

- Next, we add a DatabaseFactory class which inherit from the class: Disposable and implement the interface IDatabaseFactory.

Page 16: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

public class DatabaseFactory : Disposable, IDatabaseFactory { private MyFinanceContext dataContext; public MyFinanceContext DataContext { get { return dataContext; } }

public DatabaseFactory() { dataContext = new MyFinanceContext(); } protected override void DisposeCore() { if (DataContext != null) DataContext.Dispose(); }

}

-This class implement the design pattern Factory, in fact before talking about this design pattern, let’s see two great principals that stands on the base of many design and architecture decisions.

Separation of Concerns (SoC) – is the process of breaking a computer program into distinct features that overlap in functionality as little as possible. A concern is any piece of interest or focus in a program. Typically, concerns are synonymous with features or behaviors.

Single Responsibility Principle (SRP) – every object should have a single responsibility, and that all its services should be narrowly aligned with that responsibility. On some level Cohesion is considered as synonym for SRP.

The separation allows:

● To allow people to work on individual pieces of the system in isolation;● To facilitate reusability;● To ensure the maintainability of a system;● To add new features easily;● To enable everyone to better understand the system;

-Therefore we choose the Factory pattern which will be responsible for the instantiation of our Context and will act as a factory that create the Context object and yield it to the other classes. So, as we can see this class is divided into two parts.

1. The first part instantiate the MyFinanceContext in the first call2. The second part dispose the current object.

Step 4 :-Let’s move now to the implementation of CRUD methods. No , we won’t use the DAO classes. Why?

-In fact, the pattern DAO is an anti-pattern rather than a design pattern. Supposing that we have 100 pocos, then we have to create 100 DAO classes where we will replicate the same code 100 times.

-Moreover , when we want to modify the behavior of an update method for example , then we have to do the same thing 100 times.

-Therefore , we will use the Repository pattern. The repository pattern is an abstraction layer which provides a well-organised approach to maintaining a separation between an application's data access and business logic layers. This gives us the important advantages of making code more maintainable

Page 17: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

and readable and improving the testability of our code. It also works great with dependency injection!

-Let’s add first an interface IRepository.

public interface IRepository<T> where T : class { void Add(T entity); void Update(T entity); void Delete(T entity); void Delete(Expression<Func<T, bool>> where); T GetById(long Id); T GetById(string Id); T Get(Expression<Func<T, bool>> where); IEnumerable<T> GetAll(); IEnumerable<T> GetMany(Expression<Func<T, bool>> where); }

-Then we will add an RepositoryBase class. In the first hand, we create this abstract class is a generic class which contain generics CRUD methods. In the second hand , we’ll add the different repositories which inherit from this base Repository.

-As we see in this class, we pass a DatabaseFactory object through the constructor and we create a generic Set since this Set will be used by the different entities.

-After getting the Context object created by the DatabaseFactory we add some generics methods.

-Note that in somes methods like public virtual void Delete(Expression<Func<T, bool>> where)

we can pass a lambda expression to add a criteria instead of creating several methods to delete by criteria.

public abstract class RepositoryBase<T> : IRepository<T> where T : class { private MyFinanceContext dataContext; private IDbSet<T> dbset; IDatabaseFactory databaseFactory; protected RepositoryBase(IDatabaseFactory dbFactory) { this.databaseFactory = dbFactory; dbset = DataContext.Set<T>(); } protected MyFinanceContext DataContext { get { return dataContext = databaseFactory.DataContext; } } public virtual void Add(T entity) { dbset.Add(entity); } public virtual void Update(T entity) { dbset.Attach(entity); dataContext.Entry(entity).State = EntityState.Modified; } public virtual void Delete(T entity) { dbset.Remove(entity); }

Page 18: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

public virtual void Delete(Expression<Func<T, bool>> where) { IEnumerable<T> objects = dbset.Where<T>(where).AsEnumerable(); foreach (T obj in objects) dbset.Remove(obj); } public virtual T GetById(long id) { return dbset.Find(id); } public virtual T GetById(string id) { return dbset.Find(id); } public virtual IEnumerable<T> GetAll() { return dbset.ToList(); } public virtual IEnumerable<T> GetMany(Expression<Func<T, bool>> where) { return dbset.Where(where).ToList(); } public T Get(Expression<Func<T, bool>> where) { return dbset.Where(where).FirstOrDefault<T>(); } }

Now , we create a “Repositories” Folder to add the different repositories. Then we add the following repositories CategoryRepository, ProviderRepository, ProductRepository. Those classes inherit from the BaseRepository ,

thus we don't need to replicate CRUD methods , we can just add some specific methods in those repositories.

public class CategoryRepository : RepositoryBase<Category>, ICategoryRepository { public CategoryRepository(IDatabaseFactory dbFactory) : base(dbFactory) { }

} public interface ICategoryRepository : IRepository<Category> { }

public class ProviderRepository : RepositoryBase<Provider>, IProviderRepository { public ProviderRepository(IDatabaseFactory dbFactory) : base(dbFactory) { } } public interface IProviderRepository : IRepository<Provider> { }

Page 19: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

public class ProductRepository : RepositoryBase<Product>, IProductRepository { public ProductRepository(IDatabaseFactory dbFactory) : base(dbFactory) {

} } public interface IProductRepository : IRepository<Product> { }

Step 10 :-Now we will see the last design pattern in our project The Unit Of Work.

-The idea is that we can use the Unit of Work to group a set of related operations

– the Unit of Work keeps track of the changes that we are interested in until we are ready to save them to the database.

-The pattern Unit Of Work consists in making one or more transactions database committed or rolled back together.

-The pattern "Unit of work" is used to:

-Group several "repositories" so they share a context of unique database (DbContext).

-Apply the SaveChanges () method on the instance of the context defined and ensure that any changes connected to each other will be made in a coordinated manner.

-Let’s add the next interface IUnitOfWork in the Infrastructure folder:

public interface IUnitOfWork : IDisposable { void Commit(); IProviderRepository ProviderRepository { get; } ICategoryRepository CategoryRepository { get; } IProductRepository ProductRepository { get; } }

-Then add The UnitOfWork class:

public class UnitOfWork : IUnitOfWork { private MyFinanceContext dataContext; IDatabaseFactory dbFactory; public UnitOfWork(IDatabaseFactory dbFactory) { this.dbFactory = dbFactory; }

Page 20: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

private IProviderRepository providerRepository; public IProviderRepository ProviderRepository { get { return providerRepository = new ProviderRepository(dbFactory); } } private ICategoryRepository categoryRepository; public ICategoryRepository CategoryRepository { get { return categoryRepository = new CategoryRepository(dbFactory); } } private IProductRepository productRepository; public IProductRepository ProductRepository { get { return productRepository = new ProductRepository(dbFactory); } } protected MyFinanceContext DataContext { get { return dataContext = dbFactory.DataContext; } } public void Commit() { DataContext.SaveChanges(); } public void Dispose() { dbFactory.Dispose(); } }

Part 8 – Business LayerStep 1 :-We move to the business layer (MyFinance.Service), Let’s add a service to encapsulate the methods implemented in the data layer:

public interface IEBuyService: IDisposable { void CreateProduct(Product p); Biological GetBiologicol(int id); IEnumerable<Category> GetCategories(); Chemical GetChemical(int id); IEnumerable<Chemical> GetChemicals(); Product GetProduct(int id); IEnumerable<Product> GetProducts(); IEnumerable<Product> GetProductsByCategory(string categoryName); void UpdateProduct(Product p); }

public class EBuyService : IEBuyService { DatabaseFactory dbFactory = null; IUnitOfWork utOfWork = null; public EBuyService() { dbFactory = new DatabaseFactory();

Page 21: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

utOfWork = new UnitOfWork(dbFactory); } public IEnumerable<Category> GetCategories() { var categories = utOfWork.CategoryRepository.GetAll(); return categories; } IEnumerable<Biological> GetBiologicols() { var Biologicals = utOfWork.ProductRepository.GetAll().OfType<Biological>(); return Biologicals; } public IEnumerable<Product> GetProducts() { var Products = utOfWork.ProductRepository.GetAll(); return Products; } public IEnumerable<Chemical> GetChemicals() { var Chemicals = utOfWork.ProductRepository.GetAll().OfType<Chemical>(); return Chemicals; } public Biological GetBiologicol(int id) { var Biological = utOfWork.ProductRepository.GetById(id) as Biological; return Biological; } public Chemical GetChemical(int id) { var Chemical = utOfWork.ProductRepository.GetById(id) as Chemical; return Chemical; } public void CreateProduct(Product p) { utOfWork.ProductRepository.Add(p); utOfWork.Commit(); } public Product GetProduct(int id) { var Product = utOfWork.ProductRepository.GetById(id); return Product; } public void UpdateProduct(Product p) { utOfWork.ProductRepository.Update(p); utOfWork.Commit(); } public IEnumerable<Product> GetProductsByCategory(string categoryName) { return utOfWork.ProductRepository.GetMany(x => x.Category.Name == categoryName); } public void Dispose() { utOfWork.Dispose(); } }

Page 22: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

Part 9 – Product Insertion

Step 1 : Controller preparation

1. Delete the old “ProductsController” class and the “Products” folder under the views folder2. Create a new Controller with empty actions

3. Instanciate the “EBuyService” class in the default constructor of the controller

IEBuyService service = null;public ProductsController(){ service = new EBuyService();}

4. Implement the disposibal pattern in the controller by overrinding the Dispose methode

protected override void Dispose(bool disposing){ if (disposing) { service.Dispose(); } base.Dispose(disposing);}

Step 2 : CreateBiological get action Coding

1. Add the CreateBiological Action

Page 23: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

public ActionResult CreateBiological(){ var categories = service.GetCategories(); ViewBag.Category = new SelectList(categories, "CategoryId", "Name"); return View();}

Step 3 : CreateBiological view Coding

1. Right click on the action name and choose « add View »

2. Generate a form for the product insertion.

3. Explore the generated view under the “Products” folder, and change the Html.BeginForm() method to the folowing

Html.BeginForm("CreateBiological", "Products", FormMethod.Post, new { enctype = "multipart/form-data" })

Now, you have a multi-part form and so you can upload files with your data.

4. Change the editor for the image name from a simple text box to a file upload input

@Html.Editor("file", new { htmlAttributes = new { @class = "form-control", type = "file" } })

Page 24: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

5. Change the “CategoryId” editor to enable the category selection by a drop down list.

@Html.DropDownListFor(model => model.CategoryId, (SelectList)ViewData["Category"], new { htmlAttributes = new { @class = "form-control" } })

6. Add a checkbox under the drop down list to check if the inserted product is a new One !

<div class="form-group"> @Html.Label("New ?", htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.CheckBox("isNew", new { htmlAttributes = new { @class = "form-control" } }) </div> </div>

This is a hole code of the “CreateBiological.cshtml” view :

@model MyFinance.Domain.Entities.Biological

@{ ViewBag.Title = "CreateBiological";}

<h2>CreateBiological</h2>

@*first change*@@using (Html.BeginForm("CreateBiological", "Products", FormMethod.Post, new { enctype = "multipart/form-data" })){ @Html.AntiForgeryToken()

<div class="form-horizontal"> <h4>Product Info :</h4> <hr /> @Html.ValidationSummary(true, "", new { @class = "text-danger" }) <div class="form-group"> @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" }) </div> </div>

<div class="form-group"> @Html.LabelFor(model => model.Description, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Description, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Description, "", new { @class = "text-danger" }) </div> </div>

<div class="form-group"> @Html.LabelFor(model => model.Price, htmlAttributes: new { @class = "control-label col-md-2" })

Page 25: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

<div class="col-md-10"> @Html.EditorFor(model => model.Price, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" }) </div> </div>

<div class="form-group"> @Html.LabelFor(model => model.Quantity, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Quantity, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Quantity, "", new { @class = "text-danger" }) </div> </div> @*second change*@ <div class="form-group"> @Html.LabelFor(model => model.ImageName, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.Editor("file", new { htmlAttributes = new { @class = "form-control", type = "file" } }) @Html.ValidationMessageFor(model => model.ImageName, "", new { @class = "text-danger" }) </div> </div>

<div class="form-group"> @Html.LabelFor(model => model.DateProd, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.DateProd, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.DateProd, "", new { @class = "text-danger" }) </div> </div> @*modif 3*@ <div class="form-group"> @Html.LabelFor(model => model.CategoryId, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.DropDownListFor(model => model.CategoryId, (SelectList)ViewData["Category"], new { htmlAttributes = new { @class = "form-control" } }) </div> </div> @*modif 4*@ <div class="form-group"> @Html.Label("New ?", htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.CheckBox("isNew", new { htmlAttributes = new { @class = "form-control" } }) </div> </div>

<div class="form-group"> @Html.LabelFor(model => model.Herbs, htmlAttributes: new { @class = "control-label col-md-2" })

Page 26: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

<div class="col-md-10"> @Html.EditorFor(model => model.Herbs, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Herbs, "", new { @class = "text-danger" }) </div> </div>

<div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" class="btn btn-default" /> </div> </div> </div>}

<div> @Html.ActionLink("Back to List", "Index")</div>

@section Scripts { @Scripts.Render("~/bundles/jqueryval")}

Step 4 : CreateBiological post action Coding

Let’s add a post action so the server can handel the product, file and the checkbox data.First, we will validate these data, and save it in “Session” or “TempData” type and finally we will redirect the user the another view for validation before insertion.

public ActionResult CreateBiological(Biological bio, HttpPostedFileBase file, bool? isNew){ if (!ModelState.IsValid || file.ContentLength == 0 || isNew == null) { return CreateBiological(); }

bio.ImageName = file.FileName;

Session["Product"] = bio; TempData["isNew"] = isNew; TempData["Image"] = file; return RedirectToAction("ValidateBiological");

}

Step 5 : “ValidateBiological” get action Coding

1. Now we add another get action called “ValidateBiological” that do two things based on a Boolean value :

Display the product details view, so the client can check data before validation Insert the product in the data base and save the file on the server.

public ActionResult ValidateBiological (bool? insertion) { Product p = Session["Product"] as Product;

Page 27: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

if (insertion == true) { HttpPostedFileBase file = TempData["Image"] as HttpPostedFileBase; if (file.ContentLength > 0) { service.CreateProduct(p); var path = Path.Combine(Server.MapPath("~/Content/Upload"), p.ImageName); file.SaveAs(path); } return RedirectToAction("Index"); } else { return View(p); } }

2. Add a new folder named “Upload” under the “Content” Folder3. Change the following configuration <httpRuntime targetFramework="4.5" /> in the

Web.config file to increase the maximum upload file size from 80KB to 10MB<httpRuntime targetFramework="4.5" executionTimeout="3600" maxRequestLength="102400" appRequestQueueLimit="100" requestValidationMode="2.0" requestLengthDiskThreshold="10024000"/>

Step 6 : “ValidateBiological” view Coding

1. Right click on the “ValidateBiological” action name and choose « add View »

2. Generate a view for the product details.

Page 28: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

3. Modify the generated view as the folowing : Get the isNew boolean value from the TempData Dictionary Display a big title if it’s a new product or a small one Add a validation action link and a cancel action link

@model MyFinance.Domain.Entities.Biological

@{ ViewBag.Title = "ValidateBiological"; bool? isNew = Convert.ToBoolean(TempData["isNew"]);}

<h2>Validate Biological</h2>

<div> @if (isNew == true) { <h1>New Biological Product !!</h1> } else { <h4>Biological Product !!</h4> } <hr /> <dl class="dl-horizontal"> <dt> @Html.DisplayNameFor(model => model.Description) </dt>

<dd> @Html.DisplayFor(model => model.Description) </dd>

<dt> @Html.DisplayNameFor(model => model.Name) </dt>

<dd> @Html.DisplayFor(model => model.Name) </dd>

<dt> @Html.DisplayNameFor(model => model.Price)

Page 29: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

</dt>

<dd> @Html.DisplayFor(model => model.Price) </dd>

<dt> @Html.DisplayNameFor(model => model.Quantity) </dt>

<dd> @Html.DisplayFor(model => model.Quantity) </dd>

<dt> @Html.DisplayNameFor(model => model.ImageName) </dt>

<dd> @Html.DisplayFor(model => model.ImageName) </dd>

<dt> @Html.DisplayNameFor(model => model.DateProd) </dt>

<dd> @Html.DisplayFor(model => model.DateProd) </dd>

<dt> @Html.DisplayNameFor(model => model.CategoryId) </dt>

<dd> @Html.DisplayFor(model => model.CategoryId) </dd>

<dt> @Html.DisplayNameFor(model => model.Herbs) </dt>

<dd> @Html.DisplayFor(model => model.Herbs) </dd>

</dl>

</div><p> @Html.ActionLink("Confirmation", "ValidateBiological", new { insertion = true }) | @Html.ActionLink("Cancel", "Index")</p>

Step 7 : Run and Test

Run the application, insert some products and check the database.

Step 8 : Chemical product insertion

Page 30: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

Repete the same steps for chemical product insertion.

Part 10 – Product IndexStep 1 : Index action coding

1- Implement the ProductController Index action to return a View with the list of products.

Step 2 - Creating the Index View

In this task, you will create the Index View template to display the list of products returned by

the Product Controller.

1. Right-click inside the Index action method and select Add View. This will bring up

the Add View dialog.

Step 3 - Customizing the scaffold of the Index View

In this task, you will adjust the simple View template created with ASP.NET MVC scaffolding

feature to have it display the fields you want.

Note: The scaffolding support within ASP.NET MVC generates a simple View template

which lists all fields in the Product model. Scaffolding provides a quick way to get started on

a strongly typed view: rather than having to write the View template manually, scaffolding

quickly generates a default template and then you can modify the generated code.

public ActionResult Index(){ var products = service.GetProducts(); return View(products);}

Page 31: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

1. Review the code created. The generated list of fields will be part of the following HTML

table that Scaffolding is using for displaying tabular data.

2. Replace the code under the title <h2>Index</h2> by the next code

-

We use the Razor View Engine and HTML helpers to generate HTM tags. For example the @Html.TextBox("categoryName ") Helper will generate the next tag:

<input id='categoryName' name='categoryName' />

-Note: To understand Razor, you can view this blog http://weblogs.asp.net/scottgu/archive/2010/07/02/introducing-razor.aspx.

And this blog for HTML Helper

http://www.mikesdotnetting.com/Article/184/HTML-Helpers-For-Forms-In-Razor-Web-Pages

-Back to the code this view, the Html.BeginForm() Helper will generate a form which will send the data by default to the current action Index located in the ProductController.

@model IEnumerable<MyFinance.Domain.Entities.Product>

@{ ViewBag.Title = "Index";}

<h2>Index</h2>

@using (Html.BeginForm()){ <table> <tr> <td> <div> Search by category: @Html.TextBox("categoryName")

</div> </td> <td> <input type="submit" value="Search" id="submit" /> </td> <td> @ViewBag.Message

</td> </tr> </table>}

<div id="divExpenseList"> <p> @Html.ActionLink("Create New", "CreateBiological") </p></div>

Page 32: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

-The Form contain the buttom <input type="submit" value="Search" id="submit" /> which send the data extracted from the TextBox to the action Index.

-In fact when a form send data to the controller, we need another version of the current action. In our case the Index action. To make the difference between the two actions named Index, the second version which retrieve data from the view will be decorated by the attribute [HttpPost], the first action will use by default the Get mode.

-

Before implementing this action, we will continue with our View. The next Helper @Html.ActionLink("Create New", "CreateBiological") will generate an Hyperlink.It should redirect to The CreateBiological action.

-Before moving to the controller, we notice that this view lacks the display part, where we display the list of products retrieved from the database.

- Step 4 – Working with Partial View

- A partial view is used when you have some view component that is used in more than one place, or is better separated in to a separate file (for readability, for example).

-In our case, instead of displaying the list of products in this view, we will create a partial view where we will display the description, the price and the image of a product. Then,in the Index view we will display this partial view as well as we have products.

-Let’s add our partial view, Right click on the Product folder located in Views folder, then Add View:

[HttpPost]

public ActionResult Index(string categoryName)

{

}

Page 33: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

Let’s add the next code:

@{string path = "~/Content/Upload/" + @Model.ImageName;}<div style="float:left; margin:5px;"> <p>@Model.Name</p> <img alt="Produit" src="@Url.Content(path)" width="50" height="50" /> <p>@Model.Description</p> <p>@Model.Price</p> <p>@Html.ActionLink("Details", "Details", new { id = Model.ProductId })</p> <p>@Html.ActionLink("Edit", "Edit", new { id = Model.ProductId })</p></div>

-This partial view is strongly typed. First we create a string field where we store the hole path of the image. Then we display the imge using @Url.Content(path) Helper which converts a virtual (relative) path to an application absolute path

-The Model object contain the Product object passed from the Controller.

-The >@Html.ActionLink("Details", "Details",new { id = Model.ProductId }) will generate an HyperLink which redirect to the Details action. This tag will send the value of the ProductId of the current product object to the Details action.

Let’s adding a custom Helper.

- Step 5 – Adding an HTML Helper

- The Desription properties can be long. In this step you will learn how to add a custom HTML helper to truncate that text.

Page 34: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

- In this task, you will add a new method Truncate to the HTML object exposed within ASP.NET MVC Views. To do this, you will implement an extension method to the built-in System.Web.Mvc.HtmlHelper class provided by ASP.NET MVC.

- Add the following code below the @model directive to define the Truncate helper method.

@helper Truncate(string input, int length){ if (input.Length <= length) { @input } else { @input.Substring(0, length)<text>...</text> }}

- Replace the lines that show the Product Description . <p>@Model.Description</p> by

the following line<p>@Truncate(Model.Description, 25)</p>

- Step 6 – Calling the partial view

-Backing to the Index View. Now we will call the partial view to show the list of products from the database.

-Add the next code to the Index View.

-After finishing the Index View, we move to the ProductController to implement the second version of the Index action.

Step 7 – Implementing the HTTP-POST Index action method

-After implementing the HTTP-GET Index Action Method, we will implement now the HTTP-POST version.

-Add the next code in the ProductController.

<div style="display:block;"> @if (Model != null) { foreach (var item in Model) {

@Html.Partial("_DisplayProduct", item)

} }</div>

Page 35: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

-This action retrieve a string which present the category chosen by the user from the view. Then retrieve the list of products by category, and return the lists of products to the view.

-In case of exception, we use the ViewBag which present a dynamic property and can store data and pass it from controller to view.

Step 8 : Run and Test

Part 11 – Product Update

Step 1 – Get Edit Action

Modify the Get edit Action as the following:

public ActionResult Edit(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } Biological p = service.GetBiologicol(id.Value); if (p == null) { return HttpNotFound(); } return View(p); }

Step 2 – Scaffold the viewRight click on the Edit action name and add a view with Edit Template for a biological product :

public ActionResult Index(string categoryName){ try { var products = service.GetProductsByCategory(categoryName); return View(products); } catch (Exception) {

ViewBag.Message = "The category doesn't exist"; return View(); }}

Page 36: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

Step 3 – Post edit Action

Modify the Post edit Action as the following:

[HttpPost] public ActionResult Edit(Biological bio) { if (ModelState.IsValid) { service.UpdateProduct(bio); return RedirectToAction("Index"); } return View(bio); }

Step 7 : Run and Test

Part 12 – Dependecy Injection

DI is a software design pattern that allow us to develop loosely coupled code. DI is a great

way to reduce tight coupling between software components. DI also enables us to better

manage future changes and other complexity in our software. The purpose of DI is to make

code maintainable.

The Dependency Injection pattern uses a builder object to initialize objects and provide

the required dependencies to the object means it allows you to "inject" a dependency from

outside the class.

-Dependency Injection means that objects do not create other objects on which they rely to

do their work. Instead, they get the objects that they need from an outside source

-At a high level, the goal of Dependency Injection is that a client class (e.g. the golfer) needs

something that satisfies an interface (e.g. IClub). It doesn't care what the concrete type is

Page 37: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

(e.g. WoodClub, IronClub, WedgeClub or PutterClub), it wants someone else to handle that

(e.g. a goodcaddy). The Dependency Resolver in ASP.NET MVC can allow you to register

your dependency logic somewhere else (e.g. a container or a bag of clubs).

The advantages of using Dependency Injection pattern and Inversion of Control are the following:

Reduces class coupling

Increases code reusing

Improves code maintainability

Improves application testing

What is DI Container

A DI Container is a framework to create dependencies and inject them automatically

when required. It automatically creates objects based on request and inject them when

required. DI Container helps us to manage dependencies with in the application in a simple

and easy way.

We can also manage an application dependencies without a DI Container, but it will be like

as POOR MAN’S DI and we have to do more work, to make it configured and

manageable.

List of popular DI Container for .Net

Page 38: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

Today, there are a lot of excellent DI Containers that are available for .NET. Here, the list of

most useful DI Container for .Net framework.

-Castle Windsor

-Spring.NET

-Autofac-StructureMap-Unity-Ninject

-We will use Unity, the Dependency Injection of Microsft.

Step 1: Injecting a Constructor

-Abore all projects in our solution we use constructor to inject abstract objects, for example in the ProductController we pass the ProductService and the CategoryService in constructor. So we are not obliged to instanciate classes existing in other projet which can make ours projects high coupleds.

Step 2: Including Unity into MvcFinance Solution

In this task, you will include Unity bootstrapper for ASP.NET MVC  NuGet Package to the solution.

Note: Unity is a lightweight, extensible dependency injection container with optional support for instance and type interception. It is a general-purpose container for use in any type of .NET application. It provides all the common features found in dependency injection mechanisms including: object creation, abstraction of requirements by specifying dependencies at runtime and flexibility, by deferring the component configuration to the container.

-Install Unity bootstrapper for ASP.NET MVC NuGet Package in the MyFinance.Web project. Righ Click on the projet -> Manage NuGet Packages:

IEBuyService service = null; public ProductsController(IEBuyService service) { this.service = service; }

Page 39: EntityFrameworkCodeFirst&AspMVC 2.0 (2).docx

Step 3 - Registering Types in Unity container

Open the “Unityconfig” class in the “App-Start” folder in the “MyFinance.Web” Project and add this

code in the “RegisterTypes” method.

container.RegisterType<IEBuyService, EBuyService>( new PerRequestLifetimeManager());container.RegisterType<IUnitOfWork, UnitOfWork>( new PerRequestLifetimeManager());container.RegisterType<ICategoryRepository, CategoryRepository>( new PerRequestLifetimeManager());container.RegisterType<IProviderRepository, ProviderRepository>( new PerRequestLifetimeManager());container.RegisterType<IProductRepository, ProductRepository>( new PerRequestLifetimeManager());container.RegisterType<IDatabaseFactory, DatabaseFactory>( new PerRequestLifetimeManager());

Step 4 - Running the Application

In this task, you will run the application to verify that it can now be loaded after including Unity