ASP.NET MVC With Dapper?

September 24, 2016 Leave a comment

Hello fellow coders.

It’s a while again. I’m a lazy, lazy coder, and I don’t have much time updating this blog.

Let’s get talking.

Entity Framework is a wonderful technology. It rescues us from the burden of creating & managing our business classes and CRUD operations within the data layer. It makes our lives easier. It even generates views including DropDownListFor for foreign key relations. Wonderful!

Or does it?

Okay, I love the framework, but it sucks. It is slow, and even slower at being slow. Also, if you are not using Entity Framework, the foreign key relations within a custom designed class is not seen by Scaffolding engine. It only scaffolds generic fields, skipping Foreign Keys and Relations entirely.

I’m using Dapper Micro-ORM for a while now (over 1 year actually). I have successfully completed several mid-sized projects with it. It is a thin layer over standard ADO.NET and it operates fast, and by that, I mean really, really fast.

One caveat is that, you have to manually code your classes, your annotations (Required, DisplayName..), your relationships, etc., and you have to create your foreign key relations (and also dropdown logic).

Tired of doing these over and over, I have created a model, metadata,  view and controller generator which generates all of these for me.

Let’s have a look.

For the sake of simplicity, I have 4 tables, as shown here.

db1

Next, I have decorated the tables and fields with the names I want to see in my views. This is a wonderful thing for non-English users like me.

db2

These settings are used for generating models and views. Now, I open my generator🙂

db3

Set the options, and click Start. Easy enough!

The generator then creates this structure under the selected folder

db4:

Here is the generated Order Model:

using System;
using System.Collections.Generic;
using System.Linq;
using Models;
using Dapper;

namespace Models
{
	public partial class Order
	{
		#region Primary Keys
		public int Id { get; set; }
		#endregion

		#region Foreign Keys
		public int CustomerId { get; set; }
		#endregion

		#region Generic Fields
		public string Name { get; set; }
		public DateTime OrderDate { get; set; }
		#endregion

		#region Virtual Fields
		public virtual Lazy<Customer> Customer { get { return new Lazy<Customer>(() => new Customer().FetchById((int)CustomerId)); } }
		public virtual Lazy<IEnumerable<Customer>> CustomerList { get { return new Lazy<IEnumerable<Customer>>(() => new Customer().FetchAll()); } }
		#endregion

		#region Methods

		#region Create Method
		public Order Create(Order order)
		{
			this.Id = Database.Connection.Query<int>("INSERT INTO [dbo].Order(CustomerId, Name, OrderDate) VALUES(@CustomerId, @Name, @OrderDate); SELECT CAST(SCOPE_IDENTITY() as int)", order).Single();
			return order;
		}
		#endregion

		#region Fetch By Primary Keys
		public Order FetchById(int id)
		{
			return Database.Connection.Query<Order>("SELECT * FROM [dbo].Order WHERE Id = @Id", new { Id = id } ).SingleOrDefault();
		}
		#endregion

		#region FetchBy Fields
		public Order FetchByName(string name)
		{
			return Database.Connection.Query<Order>("SELECT * FROM [dbo].Order WHERE Name = @Name", new { Name = name } ).SingleOrDefault();
		}

		public Order FetchByOrderDate(DateTime orderDate)
		{
			return Database.Connection.Query<Order>("SELECT * FROM [dbo].Order WHERE OrderDate = @OrderDate", new { OrderDate = orderDate } ).SingleOrDefault();
		}

		#endregion

		#region FetchAll
		public List<Order> FetchAll()
		{
			return Database.Connection.Query<Order>("SELECT * FROM [dbo].Order").ToList();
		}
		#endregion

		#region FetchAllBy Foreign Keys
		public List<Order> FetchAllByCustomerId(int customerId)
		{
			return Database.Connection.Query < Order > ("SELECT * FROM [dbo].Order WHERE CustomerId = @CustomerId", new { CustomerId = customerId }).ToList();
		}

		#endregion

		#region FetchAllBy Fields
		public List<Order> FetchAllByName(string name)
		{
			return Database.Connection.Query<Order>("SELECT * FROM [dbo].Order WHERE Name = @Name", new { Name = name }).ToList();
		}

		public List<Order> FetchAllByOrderDate(DateTime orderDate)
		{
			return Database.Connection.Query<Order>("SELECT * FROM [dbo].Order WHERE OrderDate = @OrderDate", new { OrderDate = orderDate }).ToList();
		}

		#endregion

		#region Update Method
		public Order Update(Order order)
		{
			Database.Connection.Execute("UPDATE [dbo].Order SET CustomerId = @CustomerId, Name = @Name, OrderDate = @OrderDate WHERE Id = @Id", order);
			return order;
		}
		#endregion

		#region Delete By Primary Keys
		public void DeleteById(int id)
		{
			var modelOrderDetails = new OrderDetails();
			modelOrderDetails.DeleteAllByOrderId(id);
			Database.Connection.Execute("DELETE FROM [dbo].Order WHERE Id = @Id", new { Id = id } );
		}
		#endregion

		#region DeleteAllBy Foreign Keys
		public void DeleteAllByCustomerId(int customerId)
		{
			Database.Connection.Execute("DELETE FROM [dbo].Order WHERE CustomerId = @CustomerId", new { CustomerId = customerId });
		}

		#endregion

		#region DeleteAllBy Fields
		public void DeleteAllByName(string name)
		{
			Database.Connection.Execute("DELETE FROM [dbo].Order WHERE Name = @Name", new { Name = name });
		}

		public void DeleteAllByOrderDate(DateTime orderDate)
		{
			Database.Connection.Execute("DELETE FROM [dbo].Order WHERE OrderDate = @OrderDate", new { OrderDate = orderDate });
		}

		#endregion

		#endregion
	}
}

Metadata class:

using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace Models
{
	[MetadataType(typeof(OrderMetadata))]
	public partial class Order
	{
	}

	public class OrderMetadata
	{
		#region Primary Keys
		[Key]
		[ScaffoldColumn(false)]
		public int Id { get; set; }
		#endregion

		#region Foreign Keys
		[DisplayName("Customer")]
		[Required(ErrorMessage="Customer is required.")]
		public int CustomerId { get; set; }
		#endregion

		#region Generic Fields
		[DisplayName("Order Name")]
		[StringLength(100)]
		[Required(ErrorMessage="Order Name is required.")]
		public string Name { get; set; }
		[DisplayName("Order Date")]
		[DataType(DataType.Date)]
		[DisplayFormat(DataFormatString = "{0:dd.MM.yyyy}", ApplyFormatInEditMode = true)]
		[Required(ErrorMessage="Order Date is required.")]
		public DateTime OrderDate { get; set; }
		#endregion

	}
}

And the controller for Order:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net;
using System.Web.Mvc;
using Models;

namespace Test.Controllers
{
	public partial class OrderController: Controller
	{
		#region Methods

		#region Helper: SetDependencies Method
		public void SetDependencies(int customerId = -1)
		{
			ViewBag.customerList = new SelectList(new Customer().FetchAll(), "Id", "CustomerName", customerId != -1 ? customerId : (int?)null);
		}
		#endregion

		#region Index: GET Method
		public ViewResult Index()
		{
			var model = new Order().FetchAll();
			return View(model);
		}
		#endregion

		#region Details: GET Method
		public ActionResult Details(int? id)
		{
			if (id == null) return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
			var model = new Order().FetchById((int)id);
			if (model == null) return HttpNotFound();
			return View(model);
		}

		#endregion

		#region New: GET Method
		public ActionResult New()
		{
			SetDependencies();
			return View();
		}

		#endregion

		#region New: POST Method
		[HttpPost]
		[ValidateAntiForgeryToken]
		public ActionResult New(Order model)
		{
			if (!ModelState.IsValid) { SetDependencies(); return View(model); }
			model.Create(model);
			return RedirectToAction("Index");
		}
		#endregion

		#region Edit: GET Method
		public ActionResult Edit(int? id)
		{
			if (id == null) return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
			var model = new Order().FetchById((int)id);
			if (model == null) return HttpNotFound();
			SetDependencies(model.CustomerId);
			return View(model);
		}

		#endregion

		#region Edit: POST Method
		[HttpPost]
		[ValidateAntiForgeryToken]
		public ActionResult Edit(Order model)
		{
			if (!ModelState.IsValid) { SetDependencies(); return View(model); }
			model.Update(model);
			return RedirectToAction("Index");
		}
		#endregion

		#region Delete: GET Method
		public ActionResult Delete(int? id)
		{
			if (id == null) return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
			var model = new Order().FetchById((int)id);
			if (model == null) return HttpNotFound();
			return View(model);
		}

		#endregion

		#region DeleteConfirmed: POST Method
		[HttpPost, ActionName("Delete")]
		[ValidateAntiForgeryToken]
		public ActionResult DeleteConfirmed(int? id)
		{
			var model = new Order();
			model.DeleteById((int)id);
			return RedirectToAction("Index");
		}
		#endregion

		#endregion
	}
}

And the view (Create)

@model Models.Order
@{
	ViewBag.Title = "New Order";
}

<div class="row st">
	<div class="col-md-12">
		@using (Html.BeginForm())
		{
			@Html.AntiForgeryToken()
			<div class="panel panel-default panel-default">
				<div class="panel-heading"><strong>New Order</strong><input type="submit" class="pull-right SubmitButton" value="Save" /><span class="pull-right">&nbsp;&nbsp;</span><button onclick="location.href = '@Url.Action("Index", "Order")'; return false;" class="SubmitButton pull-right">Back</button></div>
				<div class="panel-body pbcolor">
					<div class="row">
						<div class="col-xs-12">
							<p>Please enter the details of new Order.</p>
						</div>
					</div>
				</div>
				<div class="panel-body">
					<div class="form-horizontal">
						@Html.ValidationSummary(true, "", new { @class = "text-danger" })
						<div class="form-group">
							@Html.LabelFor(model => model.CustomerId, new { @class = "control-label col-md-2" })
							<div class="col-md-10">
								@Html.DropDownListFor(model => model.CustomerId, (IEnumerable<SelectListItem>)ViewBag.customerList, new { @class = "form-control input-sm" })
								@Html.ValidationMessageFor(model => model.CustomerId, "", new { @class = "text-danger" })
							</div>
						</div>
						<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 input-sm" }})
								@Html.ValidationMessageFor(model => model.Name,"", new { @class = "text-danger" })
							</div>
						</div>
						<div class="form-group">
							@Html.LabelFor(model => model.OrderDate, htmlAttributes: new { @class = "control-label col-md-2" })
							<div class="col-md-10">
								@Html.EditorFor(model => model.OrderDate, new { htmlAttributes =  new { @class = "form-control input-sm" }})
								@Html.ValidationMessageFor(model => model.OrderDate,"", new { @class = "text-danger" })
							</div>
						</div>
					</div>
				</div>
			</div>
		}
	</div>
</div>

And voila! The project’s dependencies are generated without a single line of code. It still has plenty of room for adding more features, but hey, I have to do some coding, otherwise every project will be boring🙂

Have a very nice day!

SyncFusion Essential Studio. For free?

November 22, 2015 Leave a comment

Hello everybody!

After a long silence (again), I’m here to say that I’m alive and still coding. It’s time to add another post, and this is important.

syncfusion-logo

The wonderful guys at Syncfusion made an unbelievable move. They made their $10,000 worth of Essential Studio Enterprise Edition, which consists of hundreds high quality components and tools for ASP.NET, MVC, WPF and more, available for free, with the exception of being an individual or a small company.

As a developer, I have worked with several component packages in the past. For almost 1.5 years, I’m using Syncfusion Essential Studio and never looked back.

The tools and components are the best of the any bundle you can find. The ease of use, the overall quality and the support is definitely unmatched across vendors.

Hurry and grab your license for free. You won’t regret it.

The most beautiful present of all time: My daughter!

November 12, 2013 1 comment

Hello everybody!

The time passes so fast, that I am unable to track it anymore. Meanwhile, I wanted to show you a picture of my beloved daughter. No tech stuff this time!

Have a nice week!
ayca

Categories: Uncategorized

Frank Borland: Welcome back sherrif

December 23, 2012 4 comments

I always have a soft spot for developer tools which has Borland® Logo on it. Although I’m now making money using Microsoft products, Borland products was always first to prefer for me. I know that I am not alone with these feelings.

 

Recently, Borland released a video about the return of Frank Borland, which made me feel like I was still living in the good old times.

Here is the snippet from production agency:

Working together with integrated B2B marketing agency, True, Irresistible Films have produced an introductory film to re-establish Borland Software Corporation as leaders in software development, through awareness generated around the character Frank Borland.

Borland recognises that developers and developmental organisations need to define, manage and measure software delivery processes based on unique needs, tools and preferences, working to identify the requirements, test and change solutions that help companies build better software, faster.

Frank first appeared in advertisements during the 80s, helping to shape Borland as a dynamic company that tackled the biggest of software companies, promoting software such as Sidekick and Turbo Pascal.

Usage of the film will be geared towards targeting Borland’s CRM system of 40,000+ software developers. According to Frank, Borland creates testing software that works together with pre-existing tools in a non-restrictive of forcefully changing manner, offering simple yet powerful functionality.

Frank’s vision is simple: Keep it open, Don’t make it big, make it better. Focus on the user experience. Meet every platform need. Make it affordable. Listen to the community.

Creating, developing aand delivering better software, Frank’s return coincides with some key breakthroughs that will see Borland deliver new releases faster, alongside creating test tools that help deliver smooth engaging consumer experiences.

Borland is focused on extending their web and mobile testing capabilities across a range of platforms, helping to drive testing effort down and minimise time to market. Through application performance testing, Borland aims to bring exciting ideas and new releases to market through a cost effective model, placing affordable, powerful tools in the hands of the user.

Frank, and more directly, Borland’s, intent is to listen to the developers to deliver what’s really needed. On Frank’s return, Borland hope to bring to light some game-changing plans for software in the test environment and enterprise space.

Shot on location in Geneva, Switzerland, the film was captured in real-time, then reversed in Post, meaning Frank pretty much learnt his script in reverse, making for one serious come back!”

Here, watch it and see for yourself:

http://www.meetfrankborland.com/

I love you Borland. I always will.

Google: An evil company.

May 29, 2012 1 comment

Google. Once was a company with good intentions. Now it is everywhere, and it is doing everything to gain more money. It’s selling its users’ information, it forces its users to use his products, it runs and updates its software without showing any information on its users’ pc.

It started as a simple search engine, now it is a data warehouse which knows everything about us. It has so much information about us, that it started to become frightening. From now on, I will not use any Google service, and most of the reasons relate to privacy concerns of its users.

My personal reasons for not using Google products are:

1. Google Chrome: This was a good browser. But starting almosf 1.5  years ago,  it became a malware. Google decided to AUTOMATICALLY INSTALL GOOGLE UPDATE with every Google Chrome browser setup. There is not a simple way to remove the update system, nor disable it (for a regular user). It became a regular bloatware which we swear about regularly.

2. Google Toolbar: It comes bundled with most freeware, making them one of the quality adware. Yes, there is an easy uninstallation method for it (Add/Remove Programs), but most of my customers did not know where it came from, or how it is installed in the first place.

3. Google.com: It keeps asking to set it as default search engine (the blue bar on the top), and there is no way to set it off. People are complaining about it since 1 year, and as alwyas, Google had just ignored them.

4. Google became another Microsoft. Why we were mad at Microsoft? Because it wanted to control everything. It violated user rights in the past. It brought competetion to every field they wanted, and bought the rivals. Now Google is doing the same in every field. Browsers, Social Networking, Cellular Phones, Communication, Data Marketing and much more.

I for one, welcome our new evil overlords.

NVidia Optimus: Technoshit.

April 23, 2012 Leave a comment

Two days ago, I bought an Asus K53SV laptop with NVidia GT540M graphics. No matter what I try, the software only works on integrated Intel chip.

I searched for possible resolutions, but learned that these problems do exist for over a year, and NVidia doesn’t care.

Just look at community forum here:

http://forums.nvidia.com/index.php?showtopic=201764

These people didn’t do anything wrong. They only bought a laptop with NVidia graphics, and they are suffering.

I don’t know about company politics, but if you make your customers suffer, you will be the one who suffers at the end.

Technology should make our lives easier, not worse.

I will never buy/use/recommend anything from NVidia again.

Categories: Uncategorized Tags: , , ,

Changes, changes…

September 25, 2011 4 comments

Hello everybody, and welcome to long awaited status update😛

As you know, I was unable to post a new post for a long time. I got married with my beloved wife in 2010, July 23rd, and I am still married. Yes, it is hard to maintain control against a woman, but I assure you that it is more than hard to control your life when you are married. But my life is built on control, isn’t it? Of course. Unfortunately, her life is also built on control, because she is also a coder.

2 months ago, my wife gave birth to our blue-eyed, angel-like daughter, and I became a dad! I don’t know you, but I, at first, didn’t feel anything different. After 2 months, I now feel that this little baby will be the source of happiness for me and for my wife. It becomes indispensable with every passing second. Yes, it is very hard to keep her happy at the moment, because she cries for everything, including hunger, gas problem, before & after eating, after waking up, before waking up, before & after peeing, before & after shitting.. She is mostly awake. Currently, it is 05:42 am here, and she is still awake and making cute noises behind me, while lying on the bed. Thinking that I will go to my business after 2 hours, you may think that being a father is hard. You have not seen anything, trust me.

I do not want to scare father candidates, so I won’t scare them by writing more about it. Just a hint: Get ready for sleepless nights.🙂

As for coding front, too much have been changed in my life. I jumped into the C# bandwagon, and left Delphi and all others behind me. Ported all of my applications to C# and .NET Framework, and coding and solving problems much faster than it was with Delphi now.

I know, .NET Frameworks is a slow, huge, bloated framework for doing stuff, but it speeds up coding process. Trust me, Visual Studio 2010 is a blessing to programmers. I can finish and deploy a project nearly half of the time which I used to do with Delphi.

Will share more later, as my cutie started to cry for some unknown reason🙂

Cheers!