I recently implemented Entity Framework 4.3 into a production project. The challenge was I wanted to use the code first ideas and I didn’t want to generate a bunch of edmx files that had a lot of designer code that no one cares to understand. A couple of searches lead me to the Entity Framework Power Tools which is currently in Beta 2. This little package will allow you to reverse engineer databases into code first POCO classes.
The first time that I set up Power Tools for our project, I wanted to customize the reverse engineer code first templates. I wanted to do this to set up some coding standards including pascal casing properties and pluralizing collections. Some of the database tables also have an underscore in the table and column names which I do not want in my OR/M. In order to customize the templates open the solution that you want to use Entity Framework with, right click on the project you want to store your POCO classes, select the Entity Framework option and then Customize Reverse Engineer Templates. This will create a folder in that project called ReverseEngineerCodeFirst. Underneath this folder are three files: one for the context, one for the entity and one for the mapping.
This is a great start, you can change anything about the T4 template. I wanted to write some more custom code in order to remove underscores and pascal case some property names. This is where challenge 2 comes in. The T4 templates include a file called “EF.Utility.CS.ttinclude”. Finding this file was a chore, I finally found it was being referenced from C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\Templates\Includes. Your path might be slightly different depending on where you installed Visual Studio. Here are a couple of methods that I created to help with code standards.
Pluralize
public string Pluralize(string word) { var p = System.Data.Entity.Design.PluralizationServices.PluralizationService.CreateService(new CultureInfo("en-US")); return p.Pluralize(word); }
PascalCaseProperty
/// <summary> /// Returns the passed in identifier with the first letter changed to uppercase /// </summary> public string PascalCaseProperty(string identifier) { if (String.IsNullOrEmpty(identifier)) { return identifier; } string returnString = identifier; // If there is an underscore anywhere within the identifier // strip them out upper casing the first letter if (identifier.IndexOf("_") >= 0) { returnString = string.Empty; string[] propertySplit = identifier.Split('_'); if (propertySplit != null) { for (int i = 0; i > propertySplit.Length; i++) { if (!string.IsNullOrEmpty(propertySplit[i])) { returnString += propertySplit[i].Substring(0, 1).ToString(CultureInfo.InvariantCulture).ToUpperInvariant(); returnString += propertySplit[i].Substring(1).ToLowerInvariant(); } } } } else { returnString = identifier.Substring(0, 1).ToString(CultureInfo.InvariantCulture).ToUpperInvariant(); returnString += identifier.Substring(1).ToLowerInvariant(); } // Find out if the last two letters are ID string returnStringID = returnString.Substring(returnString.Length - 2); if (returnStringID.ToLower() == "id") { returnString = returnString.Substring(0, returnString.Length - 2) + "ID"; } return returnString; }
I created these methods in the c# ttinclude file. You can reference the code from the context.tt, entity.tt and mapping.tt with the following
Pascal Casing
<#= code.PascalCaseProperty(efHost.EntityType.Name) #>
Pluralize
<#= code.Pluralize(code.PascalCaseProperty(code.Escape(navProperty))) #>
Once you have your context, entity and mapping the way you want it, just go to the project and right click, hit Entity Framework, Reverse Engineer Code First. This will allow you to specify a database connection and the database you want to scaffold out. It might take a few minutes, depending on how many tables you have in the database.
I recently started an initiative at work to move to one O/RM. Traditionally we have created our own custom way to access our data. It has worked for our needs but with the addition of Entity Framework 5.0, now seems like a good time to move to a technology that is backed by groups that maintain and enhance the technology. We also use the Repository Pattern in our architecture. It makes for a nice abstraction between data access and business logic along with making it easy to mock up in unit testing our controllers.
The example I will be talking about is in a git repo. I generated the Northwind database from Microsoft. I used the Entity Framework Power Tools in order to reverse engineer the database to code first POCO classes.
A BaseRepository is created to hold the DBContext and to handle disposing of the context. The thought process is this will allow change tracking to take care of changes in the entities and by default handle transactions.
public interface IBaseRepository { void Dispose(); List RepositoryDatabaseErrors { get; set; } } public class BaseRepository : IBaseRepository, IDisposable { #region Constructor public BaseRepository() { this._databaseErrors = new List(); } #endregion Constructor #region Properties private List _databaseErrors; public List RepositoryDatabaseErrors { get { if (_databaseErrors == null) { _databaseErrors = new List(); } return _databaseErrors; } set { this._databaseErrors = value; } } private Web.Entity.NorthwindContext _dbContext = null; public Web.Entity.NorthwindContext DBContext { get { if (this._dbContext == null) { this._dbContext = new Entity.NorthwindContext(); } return this._dbContext; } } #endregion Properties #region Dispose Methods ~BaseRepository() { Dispose(false); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (this._dbContext != null) { this._dbContext.Dispose(); this._dbContext = null; } } #endregion Dispose Methods }
With the BaseRepository written, all other respoitories will inherit from the BaseRepository. Lets move on to the controller. For this example there is only one, HomeController. A Repository is created for the HomeController that will hold all the data access methods the controller actions need. It will consist of two methods, one to find all the employees in the northwind database and one to save the db context.
#region Repository public interface IHomeRepository : IBaseRepository { List<Employee> FindEmployees(); bool Save(); } public class HomeRepository : BaseRepository, IHomeRepository { public List<Employee> FindEmployees() { return (from e in base.DBContext.Employees select e).ToList(); } public bool Save() { try { base.DBContext.SaveChanges(); return true; } catch (System.Data.Entity.Validation.DbEntityValidationException ex) { foreach (DbEntityValidationResult result in ex.EntityValidationErrors) { base.RepositoryDatabaseErrors.Add(result); } return false; } } } #endregion Repository
The controller will have a property called Repository so the controller actions can interact with the database. In the example, a list of employees is pulled from the database then all employees are updated with a first name and last name change. The purpose is to show that the entities dont need to be re attached to the data context. The DBContext change tracker will keep track of the changes that happen. When SaveChanges is called on the DBContext it will be able to see all changes that need to happen. This is the reason why the DBContext is opened on the base. If we were to new up a DBContext every time we call a method to the database, then we would have to attach the changed entities or find another way to save them. This way allows for all alterations to happen in the business logic and the database access happen in the repository.
public class HomeController : BaseController { #region Properties public IHomeRepository Repository { get; set; } #endregion Properties #region Constructor public HomeController() { this.Repository = new HomeRepository(); } #endregion Constructor public ActionResult Index() { List<Employee> employees = this.Repository.FindEmployees(); // Updates the employees name, this will show that the change tracker of the DBContext // picks up the changes so there is no need to attach them to the context employees.ForEach(delegate(Employee currentEmployee) { currentEmployee.FirstName = "Repository"; currentEmployee.LastName = "EntityFramework"; }); if (!this.Repository.Save()) { foreach (DbEntityValidationResult result in this.Repository.RepositoryDatabaseErrors) { foreach (DbValidationError error in result.ValidationErrors) { this.ModelState.AddModelError("", error.ErrorMessage); } } } return View(); } #region Overrides protected override void Dispose(bool disposing) { // This is important. We must dispose the repository here in each controller this.Repository.Dispose(); base.Dispose(disposing); } #endregion Overrides }
I really enjoy Entity Framework as an O/RM. One thing I would like to try to change is to move the dispose of the repository to the base controller so the dev does not have to remember to call dispose on each new controller. I will post an update when we figure something out.
Redis is an open source, advanced key-value store. It is often referred to as a data structure server since keys can contain strings, hashes, lists, sets and sorted sets. This makes it a perfect solution for session state caching. With it having expiration built in, there is no external jobs that need to run to clean up old sessions.
Using the MSDN article for a custom session-state store provider as a template, I created a way to interact with Redis for all session data. I have done some testing on the solution but not extensive yet. I hope to get it implemented into Fellowship One within the next couple of days which uses session state database currently for some real testing. I created the redis solution as a github repo.
Microsoft Open Tech has created a Windows supported Redis solution on github which is what I used to test the redis based session state provider. You can compile the solutions into executables to run the redis server and other redis monitoring tools.
to implement the solution, take the RedisSessionProvider.cs file from the SessionProvider folder and put this into your project. Next we have to tell our application to use a custom session state provider by inserting the following into the web.config.
<sessionState mode="Custom" customProvider="RedisSessionStateProvider" cookieless="false" timeout="1"> <providers> <add name="RedisSessionStateProvider" type="RedisProvider.SessionProvider.CustomServiceProvider" server="localhost" port="6379" password="" writeExceptionsToEventLog="false"> </providers> </sessionState>
The values presented currently are the default redis values. These will probably change as you move your solution to production. The timeout is set to 1 currently so I could prove that session items were really dropping off the list. Also note that you can change the namespace of the custom service provider. If you do, just remember to change the type in the web.config to that namespace.
TODO List:
- It is recommended that exceptions from session to captured in the application event log. This has yet to be implemented
- I want to compiled this solution to a single dll so enhancements will be simplified. Instead of copying files and code, a quick reference to the dll will move session to redis.
I created a way to select multiple table cells in a UITableView by making a custom UITableView along with custom UITableViewCell. I will go through some of the main features of this. You can get the complete code on github.
On initialization of the table view, a notification is created to listen for the selecting of table cells. We turn off the ability for the table to allow selection. We will handle that in the table cell itself.
- (id)initWithFrame:(CGRect)frame style:(UITableViewStyle)aStyle notification:(NSString *)notification { if ((self = [super initWithFrame:frame style:aStyle])) { // Initialization code self.allowsSelection = NO; // Create a notification to select table cells self.selectedTableCells = [[NSMutableArray alloc] init]; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(notificationChangeSelectedCells:) name: [NSString stringWithFormat:@"FTPUITableView_%@", notification] object:nil]; } return self; }
The method for firing the notification first determines if the table is set up to handle multi select. If it is then it goes through some logic to determine if the cell is being asked to be selected or unselected. It will then draw the cell the way it needs to be presented.
- (void) notificationChangeSelectedCells: (NSNotification *) notification { FTPUIMultiSelectTableViewCell *notificationTableCell = (FTPUIMultiSelectTableViewCell *)[notification object]; if (self.isMultiSelect) { // If the object is not a check in table cell, we are not interested in it if ([[notification object] isKindOfClass:[FTPUIMultiSelectTableViewCell class]]) { if ([self isTableCellSelected:[notificationTableCell rowNumber]]) { [self.selectedTableCells removeObject:[NSNumber numberWithInteger:[notificationTableCell rowNumber]]]; } else { [self.selectedTableCells addObject:[NSNumber numberWithInteger:[notificationTableCell rowNumber]]]; } // Draw the cell [notificationTableCell drawCell:[self isTableCellSelected:[notificationTableCell rowNumber]]]; } } else { // get all the visible cells to deselect one of the cells NSArray *visible = [self visibleCells]; for (FTPUIMultiSelectTableViewCell *current in visible) { if (current.rowNumber != notificationTableCell.rowNumber) { current.isSelected = NO; [current drawCell:NO]; } else { current.isSelected = YES; [current drawCell:YES]; } } } }
The table cell has a few methods to draw the cell for presentation. This can be customized however you want your cell to look. The first method sets the properties of the cell. All the properties are needed for the table view to properly analyze the state of the cell.
- (void) drawCell:(NSIndexPath *)indexPath withSectionRows:(NSInteger)sectionRows hasSelector:(BOOL)selector isSelected:(BOOL)selected { [self setHasSelector:selector]; [self setRowNumber:[indexPath row]]; [self setTotalRowsInSection:sectionRows]; [self setIsSelected:selected]; [self drawCell:selected]; } - (void) drawCell: (BOOL)isHighlight { // If the cell has a selector, populate the selector view if (self.hasSelector) { if (isHighlight) { UIImage *table_row_select = [UIImage imageNamed:@"icon_check_square.gif"]; ((UIImageView *)self.imageView).image = [self scale:table_row_select toSize:CGSizeMake(20, 20)]; [self.contentView setBackgroundColor:self.highlightedColor]; } else { UIImage *hollow_image = [UIImage imageNamed:@"select_hollow.png"]; ((UIImageView *)self.imageView).image = [self scale:hollow_image toSize:CGSizeMake(20, 20)]; [self.contentView setBackgroundColor:self.unhighlightedColor]; } } [self changeLabelColors:isHighlight]; } - (void) changeLabelColors:(BOOL) selected { // Find all labels that are part of the content view for (UIView *current in [self.contentView subviews]) { if ([current isKindOfClass:[UILabel class]]) { UILabel *currentLabel = (UILabel *)current; if(selected) { [currentLabel setTextColor:[UIColor whiteColor]]; } else { [currentLabel setTextColor:[UIColor blackColor]]; } } } }
When the cell is created in the table view delegate method of cellForRowAtIndexPath the cell is given the notification name as well. Then the cell is drawn given the parameter values
NSString *arrayText = [tableResults objectAtIndex:[indexPath row]]; static NSString *CellIdentifier = @"Cell"; FTPUIMultiSelectTableViewCell *cell = (FTPUIMultiSelectTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[FTPUIMultiSelectTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; cell.selectionStyle = UITableViewCellSelectionStyleNone; // Notification name cell.notificationName = @"multi_select"; } // Creates the cell with all the necessary variables to set up custom UX presentation [cell drawCell:indexPath withSectionRows:[tableView numberOfRowsInSection:[indexPath section]] hasSelector:YES isSelected:[table isTableCellSelected:[indexPath row]]]; return cell;
The touch event of the table cell fires of the notification
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ [[NSNotificationCenter defaultCenter] postNotificationName:[NSString stringWithFormat:@"%@%@", NotificationPrefix, [self notificationName]] object:self]; }
This shows some of the features of how to do multi select in a custom UITableView. I recommend going to iOS-multi-select, grabbing the actual project and mess around with it. I would definitely be interested in any comments or concerns.