Archive

Archive for the ‘Cheating’ Category

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!

Rick Astley, you rule!

October 4, 2008 5 comments

According to BBC, Rick Astley is shortlisted for MTV “best act ever” award. I really hope this voting works well.

I realized that, I love this guy more than other “stars”. He is certainly at my top #5 stars of all time, by heart.

Go Rick! I love you!

Note: There are some guys at http://www.bestactever.com/ who makes voting easy. Just for info and educational purposes, I do not recommend cheating 🙂