Ehsan Ghanbari

Experience, DotNet, Solutions

Fluent Nhibernate Sample Project in Asp.net MVC

NHibernate is an ORM designed for Microsoft.Net, it's free and open source and it's a port of Java mapper to Dot Net. And fluent NHibernate is a separate version of NHibernate which lets you write your entities according to your business instead of starting from creating tables, Fluent NHibernate is just a fluent API for mapping classes with NHibernate. what an ORM does, is persisting object In database and then retrieving when it is needed, indeed it translates the object to the database and vice versa.

In Entity Framework, you use DbContext or objectContext(in earlier versions) to make configuration, in this case, Models or properties acts as a UnitOfWork pattern but In NHibernate by Using ISessionFactory Models are keep in a separate in-memory database. I'm going to show a simple NHibernate configuration in this article, Now let's start!

create a new MVC4 project and get the latest version of Fluent NHibernate by Nuget:

NH

Or you can go to the website and get the latest version and reference the Fluent NHibernate, now create a new class named Product : 

 

    public class Product
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual Category Category { get; set; }
    }

 

 and then add the Category Class to your Model folder in your project :

 

    public class Category
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
    }

 

you should define the properties as virtual because of lazy loading(retrieving an object or so-called data from the database when it's needed is lazy loading) , now create two separate class for mapping this Model classes via Fluent NHibernate :

 

    public sealed class ProductMapping : ClassMap<Product>
    {
        public ProductMapping()
        {
            LazyLoad();
            Table("Product");
            Id(p => p.Id);
            Id(p => p.Id).GeneratedBy.Identity();
            Map(p => p.Name);
            References(p => p.Category);
        }
    }

    public sealed class CategoryMapping : ClassMap<Category>
    {
        public CategoryMapping()
        {
            LazyLoad();
            Table("Category");
            Id(c => c.Id);
            Id(c => c.Id).GeneratedBy.Identity();
            Map(c => c.Name);
        }
     }

 

Now the most important and goal of this article is about configuration class of Fluent NHibernate, create the class with this definition

 

    public class SessionFactory : IHttpModule
    {
        private static readonly ISessionFactory _SessionFactory;
        static SessionFactory()
        {
            _SessionFactory = CreateSessionFactory();
        }
        public void Init(HttpApplication context)
        {
            context.BeginRequest += BeginRequest;
            context.EndRequest += EndRequest;
        }

        public void Dispose()
        {
        }

        public static ISession GetCurrentSession()
        {
            return _SessionFactory.GetCurrentSession();
        }

        private static void BeginRequest(object sender, EventArgs e)
        {
            ISession session = _SessionFactory.OpenSession();
            session.BeginTransaction();
            CurrentSessionContext.Bind(session);
        }

        private static void EndRequest(object sender, EventArgs e)
        {
            ISession session = CurrentSessionContext.Unbind(_SessionFactory);
            if (session == null) return;
            try
            {
                session.Transaction.Commit();
            }
            catch (Exception)
            {
                session.Transaction.Rollback();
            }
            finally
            {
                session.Close();
                session.Dispose();
            }
        }

        private static ISessionFactory CreateSessionFactory()
        {
            return Fluently.Configure()
                           .Database(MsSqlConfiguration.MsSql2008.ConnectionString(c =>    c.FromConnectionStringWithKey("DefaultConnection")))
                           .Mappings(m => m.AutoMappings.Add(CreateMappings()))
                           .CurrentSessionContext<WebSessionContext>()
                           .BuildSessionFactory();
        }

        private static AutoPersistenceModel CreateMappings()
        {
            return AutoMap
                .Assembly(System.Reflection.Assembly.GetCallingAssembly())
                .Where(t => t.Namespace != null && t.Namespace.EndsWith("Models"))
                .Conventions.Setup(c => c.Add(DefaultCascade.SaveUpdate()));
        }
    }

 

Now Open Web.config file and set the connectionString tag :

 

<connectionStrings>
    <add name="DefaultConnection" connectionString="Server=EHSAN\EHSAN;Database=NhMvcDB;Integrated Security=True" providerName="System.Data.SqlClient" />
  </connectionStrings>

 

Notice that NhMvcDB is my database name and DefaultConnection is my connectionString Name and EHSAN\EHSAN is my SQL server instance name!

You should create the Repository class to talk to the database, to make it simple I just create the ProductRepository Class (Not a Generic class for using all entities), to do that add an Interface to your Model :

 

    public interface IProductRepository
    {
        void Add(Product product);
        Product Get(int id);
        void Remove(Product product);
        IEnumerable<Product> GetAll();
        IEnumerable<Product> GetAllProductsByCategoryQuery(int categoryId);
        IEnumerable<Category> GetAllCategoriesQuery();
    }

 

And then  implement the members in ProductRepository class like this

 

    public class ProductRepository : IProductRepository
    {
        private readonly ISession _session;

        public ProductRepository()
        {
            _session = SessionFactory.GetCurrentSession();
        }
        public void Add(Product product)
        {
            SessionFactory.GetCurrentSession().Save(product);
        }

        public Product Get(int id)
        {
            return SessionFactory.GetCurrentSession().Get<Product>(id);
        }

        public void Remove(Product product)
        {
            SessionFactory.GetCurrentSession().Delete(product);
        }

        public IEnumerable<Product> GetAll()
        {
            return _session.Query<Product>();
        }

        public IEnumerable<Product> GetAllProductsByCategoryQuery(int categoryId)
        {
            var products= _session.Query<Product>();
            var productsByCategory = from c in products
                                     where c.Id == categoryId
                                     select c;
            return productsByCategory;
        }

        public IEnumerable<Category> GetAllCategoriesQuery()
        {
            return _session.Query<Category>();
        }
    }

 

Now create the Service interface

 

    public interface IProductService
    {
        void AddProduct(Product product);
        void RemoveProduct(Product productId);
        Product GetProduct(int productId);
        IEnumerable<Product> GetAllProducts();
        IEnumerable<Product> GetAllProductsByCategory(int categoryId);
        IEnumerable<Category> GetAllCategory();
    }

 

And Service implementation :

 

    public class ProductService : IProductService
    {
        private readonly IProductRepository _productRepository;
        public ProductService(IProductRepository productService)
        {
            _productRepository = productService;
        }
        public void AddProduct(Product product)
        {
            _productRepository.Add(product);
        }
        public void RemoveProduct(Product productId)
        {
            _productRepository.Remove(productId);
        }
        public Product GetProduct(int productId)
        {
            var product = new Product { Id = productId };
            return product;
        }
        public IEnumerable<Product> GetAllProducts()
        {
            var products = _productRepository.GetAll();
            return products;
        }
        public IEnumerable<Product> GetAllProductsByCategory(int categoryId)
        {
            var products = _productRepository.GetAllProductsByCategoryQuery(categoryId);
            return products;
        }
        public IEnumerable<Category> GetAllCategory()
        {
            var categories = _productRepository.GetAllCategoriesQuery();
            return categories;
        }
    }
 

 and in Controllers folder create the ProductController with this definition

 

    public class ProductController : Controller
    {
      private readonly IProductService _productService;

        public ProductController(IProductService productService)
        {
            _productService = productService;
        }

        public ActionResult List()
        {
            var products = _productService.GetAllProducts();
            return View(products);
        }

        public ActionResult Add()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Add(Product product)
        {
            if (ModelState.IsValid)
            {
                _productService.AddProduct(product);
            }
            return View();
        }
  }

 

Which list action returns the list of products and by Add action, you can add a product, about the Dependency Resolver, add Ninject by Nuget :

 

Nuget

 

Then add this configuration class to your project

 

    public class NinjectConfig
    {
        private static IKernel _ninjectKernel;
        public class NinjectDependencyResolver : DefaultControllerFactory
        {
            public NinjectDependencyResolver()
            {
                _ninjectKernel = new StandardKernel();
                ConfigurDepndency();
            }
            protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
            {
                return controllerType == null ? null : (IController)_ninjectKernel.Get(controllerType);
            }
        }
        private static void ConfigurDepndency()
        {
            _ninjectKernel.Bind<IProductRepository>().To<ProductRepository>();
            _ninjectKernel.Bind<IProductService>().To<ProductService>();
        }
    }

 

And add this line of code to your global.asax in Application_Start()

 

 ControllerBuilder.Current.SetControllerFactory(new NinjectConfig.NinjectDependencyResolver()); 

 

 end!



Apply to request response pattern in your service layer

Messaging pattern is one of my favorite patterns to use in the service layer! since I've read Pro Asp.net Design pattern by ScottMillett I've been a big fan of patterns and how to apply them, in this article I'm going to talk about request-response pattern.

"Design patterns that are associated in the realm of large-scale distributed applications like SOA systems are often referred to as Messaging patterns. Messaging patterns, like Design patterns, provide standard solutions to complex problems. Messaging patterns tackle the sharing of data in a uniform manner among many disconnected systems." [email protected]

So let's implement it, I'm going to define the News part of a project that I'm tackling with at the moment, I will just implement two operations, I have defined these methods in INewsService :

CreateNews , GetNews , GetAllNews , UpdateNews , RemoveNews , GetNewsByDate , GetAllArchivedNewsByDate

And I'm discussing CreateNews and GetAllArchivedNewsByDate .So For each of them, I should create a response and a request class. let's begin by creating the messaging classes

 

    public class CreateNewsResponse
    {
       public NewsViewModel PostViewModel { get; set; }
    }

 

This response class that returns a property of NewsViewModel type lets me access the NewsViewModel properties.  and about CreateNewsRequest I usually create a constructor contained newsViewModel as a parameter to make it using the method in service implementation and also Presentation simple

 

    public class CreateNewsRequest
    {
        internal NewsViewModel NewsViewModel { get; private set; }
        public CreateNewsRequest(NewsViewModel newsViewModel)
        {
            NewsViewModel = newsViewModel;
        }
    }

 

Now in INewsService interface, define the CreateNews like this

 

    public interface INewsService
    {
             CreateNewsResponse CreateNews(CreateNewsRequest request);
    }

 

As you can see CreateNews contains a response as an output and a request as a parameter. And as I promised, I Create messaging classes of GetAllArchivedNewsByDate :

 

    public class GetAllNewsRequest
    {
        internal NewsViewModel NewsViewModel { get; private set; }
        internal int Year { get; private set; }
        internal int Month { get; private set; }
       
        public GetAllNewsRequest(NewsViewModel newsViewModel)
        {
            NewsViewModel = newsViewModel;
        }
        public GetAllNewsRequest(int year, int month)
        {
            Year = year;
            Month = month;
        }
    }

 

As you see in the request class I've defined two constructors, first one is the same you saw in CreateNewsRequest and the second one take two parameters (year and month) because I need this constructor in presentation layer that you will see later!

And about response class

 

    public class GetAllNewsResponse
    {
        public IEnumerable<NewsViewModel> PostViewModels { get; set; }
    }

 

It returns an IEnumerable of NewsViewModel cause it maybe has more than one news in a date.

And then in INewsService I have to define the GetAllArchivedNewsByDate like this :

 

    public interface INewsService
    {
             CreateNewsResponse CreateNews(CreateNewsRequest request);
             GetAllNewsResponse GetAllArchivedNewsByDate(GetAllNewsRequest request);
    }

 

Well, about implementing these methods in NewsService take a closer look at NewsService :

 

    public class NewsService : INewsService
    {
        private readonly INewsRepository _newsPostRepository;
        private readonly IUnitOfWork _unitOfWork;
        public NewsService(INewsRepository newsPostRepository , IUnitOfWork unitOfWork)
        {
            _newsPostRepository = newsPostRepository;
            _unitOfWork = unitOfWork;
        }
        public CreateNewsResponse CreateNews(CreateNewsRequest request)
        {
            var response = new CreateNewsResponse();
            var newsPost = request.NewsViewModel.ConvertToNewsPostModel();
            newsPost.CreationTime = DateTime.Now;
            newsPost.NewsSlug = request.NewsViewModel.Title.GenerateSlug();
            _newsPostRepository.Add(newsPost);
             _unitOfWork.SaveChanges();
            return response;
        } 
        public GetAllNewsResponse GetAllArchivedNewsByDate(GetAllNewsRequest request)
        {
            var response = new GetAllNewsResponse();
            var newses = _newsPostRepository.GetAllArchivedNewsByDateQuery(request.Year, request.Month);
            response.PostViewModels = newses.ConvertToNewsViewModelList();
            return response;
        }

 

Notice about GetAllArchivedNewsByDateQuery method, it's defined in the Repository layer and it returns a value by Query Object pattern from the database.

And about ConvertToNewsViewModelList and ConvertToNewsPostModel I've talked about before in the Automapper article, I use the extension method to convert objects to each other.

So if you are solicitous about how to use these service in the presentation layer, take a look again! I'm using MVC4 in UI, here is what I've done in the controller :

 

    public class NewsController : BaseController
    {
        private readonly INewsService _newsService;
        public NewsController(ICookieStorageService cookieStorageService, INewsService newsService)
            : base(cookieStorageService)
        {
            _newsService = newsService;
        }
       public ActionResult Create()
        {
            return View("Create");
        }
        [HttpPost]
        public ActionResult Create(NewsViewModel newsViewModel)
        {
            var createNewsRequest = new CreateNewsRequest(newsViewModel);
            if (ModelState.IsValid)
            {
                _newsService.CreateNews(createNewsRequest);
                 return View("Create");
            }
            return View("Create");
        }
        public ActionResult Archive(int year, int month)
        {
            var request = new GetAllNewsRequest(year, month);
            var newses = _newsService.GetAllArchivedNewsByDate(request);
            return View("Archive", newses.PostViewModels);
        }
   }

 

As you can see in Archive ActionResult  I just used the second constructor of GetAllNewsRequest and also can use any constructor if I need! Thanks for reading this and have a good time...



Layer Supertype pattern with example in C#

First of all look at the definition by @martinfowler "A type that acts as the supertype for all types in its layer" all you need is a Supertype Class for all the Objects. I usually use it in the Repository layer as a generic Repository. I recommend to use it if you have more than one kind of object in your layer. Let's consider an example in the real world, Create a class and name it Profile

 

   public class Profile
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

 

 Then create a generic interface called IRepository

 

 public interface IRepository<T>
    {
        void Add(T entity);
        void Delete(T entity);
    }

 

Now create the IProfileRepository

 

    public interface IProfileRepository : IRepository<Profile>
    {
    }

 

Then create the Repository Class, this is the Generic Class that we talk about

 

    public class Repository<T> : IRepository<T>
    {
        public void Add(T entity)
        {
            throw new NotImplementedException();
        }

        public void Delete(T entity)
        {
            throw new NotImplementedException();
        }
    }

 

As you see you have to implement the Add and Delete methods, now if you want to create the ProfileRepository you don’t need to create the Delete and Add again

 

    public class ProfileRepository : Repository<Profile>, IProfileRepository
    {
    }

 

 That's it, Thanks for reading!



Simple command handler in .net

 

I want to introduce a simple command handler pattern in order to separate commands and queries of your applications if it’s needed. Sometimes especially in large-scale applications, you need to have two layers for reading and write separated and assign two teams to work on them.

You can use the pattern in this post based on the complexity and needs of your application. I recommend that don’t call this CQRS pattern as it’s something completely different and more complex.

 

Get started and Create an interface with no any member:

public interface ICommand

    {

    }

You will see later in this blog post that ICommand is just a flag to determine the commands for the handler. Every command which is trying to make a change in application’s state should return a result. so create another interface named ICommandResult

public interface ICommandResult

    {

        string Message { get; }

        bool Success { get; }

    }

implement the above interface as CommandResult and derive the FailureResult and SuccessResult classes from:

internal abstract class CommandResult : ICommandResult

    {

        public string Message { get; protected set; }

        public bool Success { get; protected set; }

    }



internal class FailureResult : CommandResult

    {

        public FailureResult(string message)

        {

            Success = false;

            Message = message;

        }

    }



    internal class SuccessResult : CommandResult

    {

        public SuccessResult(string message)

        {

            Success = true;

            Message = message;

        }

    }

Now create an interface for handling the validations in CommandBus class:

internal interface IValidationHandler<in TCommand> where TCommand : ICommand

    {

        IEnumerable<ValidationResult> Validate(TCommand command);

    }

 And create a class for validations:

public class ValidationResult

    {

        /// <summary>

        /// Initializes a new instance of the <see cref="ValidationResult"/> class.

        /// </summary>

        public ValidationResult()

        {

        }



        /// <summary>

        /// Initializes a new instance of the <see cref="ValidationResult"/> class.

        /// </summary>

        /// <param name="memeberName">Name of the memeber.</param>

        /// <param name="message">The message.</param>

        public ValidationResult(string memeberName, string message)

        {

            MemberName = memeberName;

            Message = message;

        }



        /// <summary>

        /// Initializes a new instance of the <see cref="ValidationResult"/> class.

        /// </summary>

        /// <param name="message">The message.</param>

        public ValidationResult(string message)

        {

            Message = message;

        }



        /// <summary>

        /// Gets or sets the name of the member.

        /// </summary>

        /// <value>

        /// The name of the member.  May be null for general validation issues.

        /// </value>

        public string MemberName { get; set; }



        /// <summary>

        /// Gets or sets the message.

        /// </summary>

        /// <value>

        /// The message.

        /// </value>

        public string Message { get; set; }

    }

And now create the most used interface in this pattern. ICommandBus will be called as bus handler in every command:

public interface ICommandBus

    {

        ICommandResult Send<TCommand>(TCommand command) where TCommand : ICommand;

        IEnumerable<ValidationResult> Validate<TCommand>(TCommand command) where TCommand : ICommand;

    }

To implementing this interface, create a class again with the following definition:

  internal class CommandBus : ICommandBus

    {

        public ICommandResult Send<TCommand>(TCommand command) where TCommand : ICommand

        {

            var handler = DependencyResolver.Current.GetService<ICommandHandler<TCommand>>();



            if (!((handler != null) && handler != null))

            {

                throw new CommandHandlerNotFoundException(typeof(TCommand));

            }

            return handler.Execute(command);

        }



        public IEnumerable<ValidationResult> Validate<TCommand>(TCommand command) where TCommand : ICommand

        {

            var handler = DependencyResolver.Current.GetService<IValidationHandler<TCommand>>();

         

            if (!((handler != null) && handler != null))

            {

                throw new ValidationHandlerNotFoundException(typeof(TCommand));

            }

            return handler.Validate(command);

        }

    }

The above class will handle every command received from the bus. And now for executing the handler or so-called for implementing the business, you need an interface:

internal interface ICommandHandler<in TCommand> where TCommand : ICommand

    {

        ICommandResult Execute(TCommand command);

    }

And finally as I’m personally interested in to have my own exception handler, so I create a customized handler:

public class CommandHandlerNotFoundException : Exception

    {

        public CommandHandlerNotFoundException(Type type)

            : base(string.Format("Command handler not found for command type: {0}", type))

        {

        }

    }



    internal class ValidationHandlerNotFoundException : Exception

    {

        public ValidationHandlerNotFoundException(Type type)

            : base(string.Format("Validation handler not found for command type: {0}", type))

        {

        }

    }

Finished! Now let’s use the above codes in a real work application. We are going to handle the products of an e-commerce application as its business is easier to comprehend for everybody:

    public interface IProductCommand : ICommand

    {

        string Name { get; set; }



        string OriginalName { get; set; }



        string Description { get; set; }



        decimal Price { get; set; }

     

    }

  

    public class ProductCommand : IProductCommand

    {

        public string Name { get; set; }



        public string OriginalName { get; set; }



        public string Description { get; set; }



        public decimal Price { get; set; }     

    }



    public class CreateProductCommand : ProductCommand

    {

    }



    public class EditProductCommand : ProductCommand

    {

        public Guid ProductId { get; set; }



        public DateTime CreationDate { get; set; }



        public DateTime LastUpdateDate { get; set; }

    }



public class DeleteProductCommand : ICommand

    {

        public Guid[] ProductIds { get; set; }

    }

You can see that I created an interface derived from ICommand named IProductCommand and finally created the target classes. And at the end we should create the Product handler class:

internal partial class ProductCommandHandler :

        ICommandHandler<CreateProductCommand>,

        ICommandHandler<EditProductCommand>,   

        ICommandHandler<DeleteProductCommand>       

    {

        private readonly IProductRepository _productRepository;

        private readonly IMembershipRepository _membershipRepository;     

        private readonly IUnitOfWork _unitOfWork;

        private readonly ICacheManager _cacheManager;

        private readonly ILogger _logger;



        public ProductCommandHandler(

            IProductRepository productRepository,        

            IUnitOfWork unitOfWork,

            ILogger logger,

            ICacheManager cacheManager)

        {

            _productRepository = productRepository;          

            _unitOfWork = unitOfWork;

            _logger = logger;

            _cacheManager = cacheManager;        

        }

       

        public ICommandResult Execute(CreateProductCommand command)

        {

            try

            {

                if (command == null)

                {

                    throw new ArgumentNullException();

                }



                var product = new Product();

                AddProductAppurtenance(command, product);

                _productRepository.Add(product);

                _unitOfWork.Commit();

                return new SuccessResult(ProductCommandMessage.ProductCreatedSuccessfully);

            }

            catch (Exception exception)

            {

                _logger.Error(exception.Message);

                return new FailureResult(ProductCommandMessage.ProductCreationFailed);

            }

        }



        public ICommandResult Execute(EditProductCommand command)

        {

            try

            {

                if (command == null)

                {

                    throw new ArgumentNullException();

                }



                var product = _productRepository.GetProductDetailById(command.ProductId);

                ClearProductAppurtenance(product);

                AddProductAppurtenance(command, product);

                _productRepository.Edit(product);

                _unitOfWork.Commit();



                return new SuccessResult(ProductCommandMessage.ProductEditedSuccessfully);

            }

            catch (Exception exception)

            {

                _logger.Error(exception.Message);

                return new FailureResult(ProductCommandMessage.ProductEditionFailed);

            }

        }



        public ICommandResult Execute(DeleteProductCommand command)

        {

            if (command.ProductIds == null)

            {

                throw new ArgumentNullException();

            }



            var exceptions = new List<Exception>();

            foreach (var productId in command.ProductIds)

            {

                try

                {

                    var product = DeleteProduct(productId);

                    _productRepository.Edit(product);

                }

                catch (Exception exception)

                {

                    exceptions.Add(exception);

                    return new FailureResult(ProductCommandMessage.ProductDeletionFailed);

                }

            }



            if (exceptions.Any())

            {

                throw new AggregateException(exceptions);

            }



            _unitOfWork.Commit();

            return new SuccessResult(ProductCommandMessage.ProductsDeletedSuccessufully);

        }  

 

We used all of the classes introduced in infrastructure.

Note 1: so you need to have an IOC container tool, to the best of my Knowledge, AsClosedTypesOf in Autofac resolves the ICommandHandler. This a piece of code I wrote for IOC handler:

  public class CommandModule : Module

    {

        protected override void Load(ContainerBuilder builder)

        {

            builder.RegisterModule<RepositoryModule>();

            builder.RegisterType<CommandBus>().As<ICommandBus>().InstancePerRequest();

            builder.RegisterAssemblyTypes(ThisAssembly).AsClosedTypesOf(typeof(ICommandHandler<>)).InstancePerRequest();

        }

    }

Note 2: a penny for your thoughts! how to use ICommandBus!? See the below piece of code as an example:

[HttpPost]

        public JsonResult DeleteProduct(DeleteProductCommand command)

        {

            var result = _commandBus.Send(command);

            return JsonMessage(result);

        }

have fun.



Introducing sqlbulktools

In my previews blog post I wrote about Z.bulkOperation. I migrated to sqlbulktools just because it's free with the same ability! (to be frank). Now to see the reason for my migration, fire up visual studio and Install the latest version of the library using the following command in console package manager:

 static void Main(string[] args)

        {



            var list = new List<User>();



            for (int i = 0; i < 100000; i++)

            {

                list.Add(new User

                {

                    Id = Guid.NewGuid(),

                    Name = "Ehsan",

                    Email = "[email protected]"

                });

               

            }



            Insert(list);



            Update(list);



            Delete(list);



        }



        public static void Insert(IList<User> users )

        {

            var bulkOperation = new BulkOperations();



            using (var trans = new TransactionScope())

            {

                using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["MyContext"].ConnectionString))

                {

                    bulkOperation.Setup<User>()

                        .ForCollection(users)

                        .WithTable("Users")

                        .AddAllColumns()

                        .BulkInsert()

                       // .SetIdentityColumn(x => x.Id, ColumnDirection.Output)

                        .Commit(connection);

                }



                trans.Complete();

            }

        }



        public static void Update(IList<User> users)

        {

            var bulkOperation = new BulkOperations();



            using (var trans = new TransactionScope())

            {

                using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["MyContext"].ConnectionString))

                {

                    bulkOperation.Setup<User>()

                        .ForCollection(users)

                        .WithTable("Users")

                        .AddAllColumns()

                        .BulkUpdate()

                        .MatchTargetOn(x => x.Id)

                        .Commit(conn);

                }



                trans.Complete();

            }

        }



        public static void Delete(List<User> list)

        {

            var bulkOperation = new BulkOperations();



            using (var trans = new TransactionScope())

            {

                using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["MyContext"].ConnectionString))

                {

                    bulkOperation.Setup<User>()

                        .ForCollection(list)

                        .WithTable("Users")

                        .AddColumn(x => x.Id)

                        .BulkDelete()

                        .MatchTargetOn(x => x.Id)

                        .Commit(conn);

                }



                trans.Complete();

            }

        }

Install-Package sqlbulktools

And get started!

Simply copy and paste the above code in your console application and run it. The result of CRUD operation with sqlbulktools  on 100000 of records in my machine would be:

insert   5,066ms

update   12,372ms

delete   2,0305ms

It could be different in every machine. But I think it's a good idea to use it in an enterprise application. Cheers!



About Me

Ehsan Ghanbari

Hi! my name is Ehsan. I'm a developer, passionate technologist, and fan of clean code. I'm interested in enterprise and large-scale applications architecture and design patterns and I'm spending a lot of my time on architecture subject. Since 2008, I've been as a developer for companies and organizations and I've been focusing on Microsoft ecosystem all the time. During the&nb Read More

Post Tags
Pending Blog Posts
Strategic design
Factory Pattern
time out pattern in ajax
Selectors in Jquery
Peridic pattern
How to query over Icollection<> of a type with linq
How to use PagedList In asp.net MVC
Domain driven design VS model driven architecture
What's the DDD-lite?
Using Generic type for type casting in F#