public class busEntry : EfCodeFirstBusinessBase< Entry,ClassifiedsContext > { }You provide two generic type parameters: The base EF Entity type (Entry in this case) and the DbContext (or EfCodeFirstContext optionally). Just doing this gives you all the base functionality of the business object which includes full CRUD operations (Load,NewEntity,Save,Delete) plus validation, error handling and a number of event hooks that allow for defaults and fixups of values before/after updates.
var entryBus = new busEntry(); var entry = entryBus.NewEntity(); entry.Title = "Title"; entry.Entered = DateTime.Now; if (!entryBus.Save()) ErrorDisplay.ShowError( entryBus.ErrorMessage ); int id = entryBus.Entity.Id // now load the saved entity from disk var entry2 = entryBus.Load(id); model.Title = entry2.Title; model.Entered = entry2.Entered; entry2.Updated = DateTime.Now; if (entryBus.Validate()) // can also happen automatically entryBus.Save();This handles all the business of creating a new entity, adding it to the context and managing lifetime of the object. It handles all basic CRUD operations so you generall don't access the DbContext directly outside of the business object itself.
public IQueryable<Entry> GetEntryList() { return Context.Entries .Take(50) .OrderByDescending(e => e.Entered); } public IQueryable<EntryListItem> GetEntryList(EntryListQueryParameters parms = null, AppTypes appType = AppTypes.Empty) { if (parms == null) parms = new EntryListQueryParameters(); if (appType == AppTypes.Empty) appType = App.Configuration.AppType; if (parms.SearchPhrase == null) parms.SearchPhrase = string.Empty; string[] searchPhrases = null; if (parms.SearchPhrase.Contains(',')) searchPhrases = parms.SearchPhrase.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); else searchPhrases = new string[1] { parms.SearchPhrase }; var entries = Context.Entries .Where(ent => ent.AppType == (int)appType && ent.IsActive && ent.Entered >= parms.StartDate && ent.Entered <= parms.EndDate) .Select( ent=> new EntryListItem() { Id = ent.Id, DisplayId = ent.DisplayId, Title = ent.Title, Description = ent.Description, CategoryId = ent.CategoryId, Entered = ent.Entered, ImageCount = ent.Images.Count(), Location = ent.Location, PriceString = ent.PriceString, Category = ent.Category, Keywords = ent.Keywords }); if (!string.IsNullOrEmpty(parms.Location)) entries = entries.Where(ent => ent.Location.StartsWith(parms.Location)); if (parms.Category > 0) { // Special Category if (parms.Category >= 1000) { if (parms.Category == (int)SpecialCategories.AllCategoriesButRealEstate) entries = entries.Where(ent => !ent.Category.Name.StartsWith("Real Estate")); } else entries = entries.Where(ent => ent.CategoryId == parms.Category); } if (!string.IsNullOrEmpty(parms.Keyword)) entries = entries.Where(ent=> ent.Keywords.Contains(parms.Keyword)); switch (parms.SortOrder) { case(EntryListSortOrder.Category): entries = entries .OrderBy(ent => ent.Category.Name) .ThenByDescending(ent => ent.Entered); break; case(EntryListSortOrder.Date): entries = entries .OrderByDescending(ent => ent.Entered); break; } return entries; }Here's a couple of operational method that updates some data (in this case from an AJAX operation on the site typically)
public bool ReportAsAbuse(int entryId, string reason, int userId, bool undoAbuse = false) { if (!undoAbuse) { // no bus object for abuses so we manually use context var abuse = new ReportedAbuse(); abuse.EntryId = entryId; abuse.Reason = reason; abuse.UserId = userId; Context.ReportedAbuses.Add(abuse); this.Load(entryId); this.Entity.IsFlagged = true; return this.Save(); // saves both abuse and entry } return UndoAbuse(entryId); } public bool IsDuplicateNewEntry(Entry entry) { // if we're not adding a new record - not a dupe if (entry.Id != 0) return false; var date = DateTime.Now.AddDays( App.Configuration.EntryExpirationDays * -1); return Context.Entries.Any(ent => ent.DisplayId == entry.DisplayId || (ent.UserId == entry.UserId && ent.Title == entry.Title && ent.Entered > date)); }Then you can also implement things like various event hooks fired before and after saving on loading etc as well as validation of the business object:
protected override bool OnBeforeSave(Entry entity) { if (entity != null) { entity.Updated = DateTime.Now; entity.AppType = (int)App.Configuration.AppType; // silently strip out 'highlight' characters entity.Title = CleanupTitle(entity.Title); entity.PriceString = this.FormatPriceString(entity.PriceString); } return true; } /// <summary> /// Overridden to handle base validation /// </summary> /// <param name="entity"></param> protected override void OnValidate(Entry entity) { base.OnValidate(entity); if (entity.CategoryId == null || entity.CategoryId == 0) ValidationErrors.Add("Please choose a category", "CategoryId"); if (string.IsNullOrEmpty(entity.Title)) ValidationErrors.Add("Please enter a title for your listing", "Title"); if (string.IsNullOrEmpty(entity.Description)) ValidationErrors.Add("Please enter a description for your listing", "Description"); if (entity.UserId == null || entity.UserId == 0) ValidationErrors.Add("You're not logged in."); if (string.IsNullOrEmpty(entity.ContactEmail) ) ValidationErrors.Add("Please provide a contact email for your listing", "ContactEmail"); } /// <summary> /// overridden to delete child images /// </summary> /// <param name="entity"></param> /// <returns></returns> protected override bool OnBeforeDelete(Entry entity) { if (entity.Images != null) entity.Images.ToList().ForEach(img => { Context.Images.Remove(img); }); return true; } protected override bool OnAfterDelete(Entry entity) { this.ExecuteNonQuery("delete from ReportedAbuses where entryId=@id",CreateParameter("@id",entity.Id)); this.ExecuteNonQuery("delete from Images where entryId=@id",CreateParameter("@id",entity.Id)); return true; }Note also that this includes the optional ability to execute raw SQL against the provider easily in a variety of ways. Optoinally if you use EfCodeFirstContext there's also an SqlNative property that provides full low level data access with classic ADO.NET support if that's ever needed (and I find that in every app there are always 1 or 2 requests that require this whether for performance or querying that simply doesn't work with LINQ or StoreProcedure call access).
>>>using System.Data.Entity; >>>using System.Linq; >>>using CardNumbers.Objects; >>> >>>namespace CardNumbers.Data >>>{ >>> public class Repository : DbContext, IRepository >>> { >>> public DbSet<Client> Clients { get; set; } >>> public DbSet<ClientOrder> ClientOrders { get; set; } >>> public DbSet<Reorder> Reorders { get; set; } >>> public DbSet<Operator> Operators { get; set; } >>> >>> IQueryable<Client> IRepository.Clients >>> { >>> get { return Clients; } >>> } >>> >>> IQueryable<ClientOrder> IRepository.ClientOrders >>> { >>> get { return ClientOrders; } >>> } >>> >>> IQueryable<Operator> IRepository.Operators >>> { >>> get { return Operators; } >>> } >>> >>> IQueryable<Reorder> IRepository.Reorders >>> { >>> get { return Reorders; } >>> } >>> >>> public void Commit() >>> { >>> this.SaveChanges(); >>> } >>> >>> public void AddClient(Client client, bool autoCommit = true) >>> { >>> Clients.Add(client) ; >>> if (autoCommit) Commit(); >>> } >>> >>> public void DeleteClient(Client client, bool autoCommit = true) >>> { >>> Clients.Remove(client); >>> if (autoCommit) Commit(); >>> } >>> >>> public void DeleteClient(int clientId, bool autoCommit = true) >>> { >>> var ReordersQuery = from reord in this.Reorders >>> where reord.ClientId == clientId >>> select reord; >>> >>> if (ReordersQuery.Any()) >>> // throw "Client " + clientId.ToString() + " can not be deleted because it has related rows in the ReOrders table!"; >>> >>> } >>> >>> >>> public void AddOperator(Operator oOperator, bool autoCommit = true) >>> { >>> Operators.Add(oOperator); >>> if (autoCommit) Commit(); >>> } >>> >>> public void DeleteOperator(Operator oOperator, bool autoCommit = true) >>> { >>> Operators.Remove(oOperator); >>> if (autoCommit) Commit(); >>> } >>> >>> public void AddOrder(ClientOrder clientorder, bool autoCommit = true) >>> { >>> ClientOrders.Add(clientorder); >>> if (autoCommit) Commit(); >>> } >>> } >>>} >>>>>>
>>>>>public void DeleteClient(int clientId, bool autoCommit = true) >>>>> { >>>>> var ReordersQuery = from reord in this.Reorders >>>>> where reord.ClientId == clientId >>>>> select reord; >>>>> >>>>> if (ReordersQuery.Any()) >>>>> //throw "Client " + clientId.ToString() + " can not be deleted because it has related rows in the ReOrders table!"; >>>>> >>>>> }>>>>>