What pattern/s can I apply on my code? I have been reading on the patterns Bridge, Command, and Builder, and it looks like I can apply them on the code block below, but I struggle at how I can apply them to my code. I've also tried adding a generic method, but I struggle with consuming it with my repository.
This is a webform backend code. I am using .Net 3.5 (can't upgrade), and C#7. Here is the code:
Entities
Note: I'm using data transfer objects because these classes have a lot of properties. Also, SpecialRequestDTO inherits StandardRequestDTO.
public class StandardRequest
{
public int RequestType { get; protected set; }
public string Name { get; protected set; }
private StandardRequest(StandardRequestDTO dto) { Name = dto.Name; }
public static StandardRequest Create(StandardRequestDTO dto) => new StandardRequest(dto);
}
public class SpecialRequest : StandardRequest
{
public string Desc { get; protected set; }
private SpecialRequest(SpecialRequestDTO dto) : base((StandardRequestDTO) dto) { Desc = dto.Desc; }
public static SpecialRequest Create(SpecialRequestDTO dto) => new SpecialRequestDTO(dto);
}
Repository
public class Repository
{
public void SaveStandardRequest(StandardRequest request)
{
var query = $"INSERT INTO Requests (Name, RequestType) Values(#{nameof(request.Name)}, #{nameof(request.RequestType)})";
// sqlcommand code etc
}
public void SaveSpecialRequest(SpecialRequest request)
{
var query = $"INSERT INTO Requests (Name, RequestType, Desc) VALUES(#{nameof(request.Name)}, #{nameof(request.Name)}, #{nameof(request.Desc)})";
// sqlcommand code etc
}
}
Index.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
string requestTypeStr = Request.Form[nameof(requestTypeStr)];
if (string.IsNullOrEmpty(requestTypeStr))
return;
}
if (requestTypeStr == 0)
{
ValidateStandardRequestFields();
var dto = CreateStandardRequestDTO();
_repository.SaveStandardRequest(dto);
}
if (requestTypeStr == 1)
{
ValidateSpecialRequestFields();
var dto = CreateSpecialRequestDTO();
_repository.SaveSpecialRequest(dto);
}
}
I took most of what I could from your post and this is what I could come up with.
Your DTO objects don't seem very clear to me, so I've left it out, but they have a role to play when it comes to saving the objects in the repository and I've left that part out.
Interface
public interface IRequest
{
int RequestType { get; set; }
string Name { get; set; }
void ValidateFields();
}
Two types of Request
public class StandardRequest : IRequest
{
public int RequestType { get ; set ; }
public string Name { get ; set; }
public void ValidateFields()
{
//validation logic
}
}
public class SpecialRequest: IRequest
{
public string Desc { get; set; }
public int RequestType { get; set; }
public string Name { get; set; }
public void ValidateFields()
{
//validation logic
}
}
Factory to create the Request objects
public class RequestFactory
{
public static IRequest CreateRequest(string requestTypeStr)
{
switch (requestTypeStr)
{
case "0": return new SpecialRequest();
default: return new StandardRequest();
}
}
}
Class to handle the interactions of the IRequest object, aptly named RequestInteractions, I know a poor name choice!
This class is what validates and saves the requests.
public class RequestInteractions
{
private IRequest _requestObj;
private Repository _repository;
public RequestInteractions(IRequest requestObj, Repository repository)
{
_requestObj = requestObj;
_repository = repository;
}
public bool ValidateAndSave()
{
try
{
_requestObj.ValidateFields();
_repository.SaveRequest(_requestObj);
return true;
}
catch (Exception e)
{
throw;
}
}
}
Repository - like I said, this needs to be fleshed out. The IRequest (through the DTO) should be able to tell you how it needs to be persisted. You'll have to fill this in.
public class Repository
{
public void SaveRequest(IRequest requestObject)
{
//The respective DTO should help you figure out what to save based on the type of IRequest
}
}
Tying it all together
var repository = new Repository();
var requestObject = RequestFactory.CreateRequest("");
var requestInteractions = new RequestInteractions(requestObject,repository);
requestInteractions.ValidateAndSave();
Benefit of this approach - You need to create a new Request class (and
a DTO) when you get a new Request to add to the system, the rest of
the plumbing need not be touched.
Downside - Well, a lot of code compared to what you have.
Related
I have an entity Order with a Status property. Status will be Enum’s like New, Processed, Disable..etc. I have set of Actions like, DeleteOrder, DuplicateOrder..etc.
Actions will be available based on status. I need to get list of Actions when I pass Instance of Order to a method. How can I achieve this. I have following pattern.
public class Order (entity)
{
public int Id { get; set; }
public OrderStatus Status { get; set; }
}
public enum OrderStatus
{
New,
Processed,
Disable
}
public class OrderActionModel
{
public int Id { get; set; }
public OrderAction Action { get; set; }
public string Comments { get; set; }
}
public enum OrderAction
{
DeleteOrder,
DuplicateOrder
}
public interface IAction
{
void Process();
}
public interface IActionFactory
{
IAction GetAction(OrderActionModel model);
List<string> GetActions(Order order);
}
public class ActionFactory : IActionFactory
{
private readonly IMailService _mailService;
public ActionFactory(IMailService mailService)
{
_mailService = mailService;
}
public IAction GetAction(OrderActionModel model)
{
switch (model.Action)
{
case DeleteOrder:
return new DeleteOrderAction(model, _mailService);
case DuplicateOrder:
return new DuplicateOrderAction(model, _mailService);
default:
return null;
}
}
public List<string> GetActions(Order order)
{
//How to call isValidAction from here for each list of actions
}
}
public class DeleteOrderAction : IAction
{
private OrderActionModel _model;
private readonly IMailService _mailService;
public DeleteOrderAction(OrderActionModel model, IMailService mailService)
{
_model = model;
_repository = repository;
}
public void Process()
{
AddAudit(_model.comments);
SendEMail();
}
public bool IsValidAction(Order order)
{
return order.Status == OrderStatus.New;
}
}
public IHttpActionResult Action(OrderActionModel model)
{
IAction action = _actionFactory.GetAction(model);
action.Process();
return Ok();
}
public IHttpActionResult GetActions(1)
{
//get order by id
var order = repo.getOrder(1)
//Some method to get Actions
var actions = SampleMethod(order)
return Ok(actions);
}
So if you want to stick with this model, the simplest way to achieve what you want would be
Dictionary<string, Func<Order, bool>> actionNameToViableCheck;
You put your actions along with their related validation functions during app initialization, so
actionNameToViableCheck.Add("Delete Order", o => DeleteOrderAction.IsValidOrder(o));
This requires the IsValidOrder method to be static.
Then your GetActions could look something like this:
public List<string> GetActions(Order order) =>
actionNameToViableCheck.Where(kv => kv.Value(order)).Select(kv => kv.Key);
Note that this is not the most effective solution if there are many different actions, because you process all of them every time. But since you define validity of an Action by its IsValidOrder method output, I don't see a much better simple way.
I've created a generic EF repository. For every deletions I need to check if my entity has a specific interface and do some changes to some other entities before remove it. How would I do that?
I tried to crate a foreach like this but it's not working.
var entitiesToRemove = context.Set<TEntity>().Where(predicate).ToList();
foreach (var entityToRemove in entitiesToRemove)
{
///
}
My current remove method
public void Remove(Func<TEntity, bool> predicate)
{
context.Set<TEntity>()
.Where(predicate).ToList()
.ForEach(del => context.Set<TEntity>().Remove(del));
}
I believe you can tackle the problem via the Strategy pattern
What follows is just one possible approach and example. You'd have to take dependency injection into consideration as well (but you can adapt this idea)
/* Your Repository implementation would probably look like this */
public class GenericRepository<TEntity>
{
private readonly DbContext context;
private readonly RemoveStrategyFactory removeStrategyFactory;
public GenericRepository(DbContext context, RemoveStrategyFactory removeStrategyFactory)
{
this.context = context;
this.removeStrategyFactory = removeStrategyFactory;
}
public void Remove(Func<TEntity, bool> predicate)
{
var entitiesToRemove = context.Set<TEntity>()
.Where(predicate).ToList();
var removeStrategy = removeStrategyFactory.GetStrategy<TEntity>();
foreach (var entity in entitiesToRemove)
{
removeStrategy.BeforeRemove(entity);
context.Set<TEntity>().Remove(entity);
}
}
}
/* SAMPLE ENTITIES */
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public List<Order> Orders { get; set; }
}
public class Order
{
public int Id { get; set; }
public Customer Customer { get; set; }
public DateTime CreatedOn { get; set; }
public bool IsArchived { get; set; }
}
/* SAMPLE STRATEGIES and FACTORY */
public abstract class RemoveStrategy<TEntity>
{
public abstract void BeforeRemove(TEntity entity);
}
public sealed class DoNothingRemoveStrategy<TEntity> : RemoveStrategy<TEntity>
{
public override void BeforeRemove(TEntity entity)
{
// Do nothing
}
}
public sealed class CustomerRemoveStrategy : RemoveStrategy<Customer>
{
public override void BeforeRemove(Customer customer)
{
// Mark all orders as archived
foreach (var order in customer.Orders)
{
order.IsArchived = true;
}
}
}
public class RemoveStrategyFactory
{
private readonly Lazy<Dictionary<Type, object>> _lazyStrategyMap;
public RemoveStrategyFactory()
{
_lazyStrategyMap = new Lazy<Dictionary<Type, object>>(InitializeStrategyMap);
}
public RemoveStrategy<TEntity> GetStrategy<TEntity>()
{
var strategyMap = _lazyStrategyMap.Value;
object strategy;
if (strategyMap.TryGetValue(typeof(TEntity), out strategy))
{
return (RemoveStrategy<TEntity>) strategy;
}
return new DoNothingRemoveStrategy<TEntity>();
}
public Dictionary<Type, object> InitializeStrategyMap()
{
return new Dictionary<Type, object>
{
// CAREFUL: for Customer type, it must be a RemoveStrategy<Customer> or derived instance
{ typeof (Customer), new CustomerRemoveStrategy() }
};
}
}
I have a problem when adding new values with a many to many mapping in Entity Framework. I know about the unit of work pattern but in our solution we would like to keep a simple repository pattern and not a unit of work class that contains everything. Is this possible or should I just implement Unit of Work right away?
If I don't use iSupplierRepository below a supplier will be added, but it will always add a new one even though there already exists one with that name.
Error:
The relationship between the two objects cannot be defined because
they are attached to different ObjectContext objects.
Repository example:
public class SupplierRepository : IntEntityRepository<Supplier, DbContext>, ISupplierRepository
{
public SupplierRepository(DbContext context) : base(context, context.Suppliers)
{
}
}
Inherited repositories:
public class IntEntityRepository<TEntity, TContext> : EntityRepository<TEntity, TContext, int>
where TEntity : class, IEntity<int>
where TContext : BaseIdentityDbContext
{
public IntEntityRepository(TContext context, IDbSet<TEntity> set) : base(context, set)
{
}
public override async Task<TEntity> GetAsync(int id)
{
return (await GetAsync(entity => entity.Id == id)).SingleOrDefault();
}
...
public abstract class EntityRepository<TEntity, TContext, TId> : IEntityRepository<TEntity, TId>
where TEntity : class, IEntity<TId>
where TContext : BaseIdentityDbContext
{
protected TContext Context { get; }
protected IDbSet<TEntity> Set { get; }
protected EntityRepository(TContext context, IDbSet<TEntity> set)
{
Context = context;
Set = set;
}
public abstract Task<TEntity> GetAsync(TId id);
...
Unity:
container.RegisterType<ISupplierRepository, SupplierRepository>();
container.RegisterType<IContactRepository, ContactRepository>();
Controller:
private readonly IContactRepository iContactRepository;
private readonly ISupplierRepository iSupplierRepository;
public ContactsController(IContactRepository iContactRepository, ISupplierRepository iSupplierRepository)
{
this.iContactRepository = iContactRepository;
this.iSupplierRepository = iSupplierRepository;
}
[HttpPut]
[Route("UpdateContact/{id}")]
public async Task<IHttpActionResult> UpdateContact(ContactViewModel contactVm, int id)
{
try
{
var supplierList = new List<Supplier>();
foreach (var contactVmSupplier in contactVm.Suppliers)
{
var supplier = await iSupplierRepository.GetAsync(contactVmSupplier.Id);
supplierList.Add(supplier);
}
var contactOriginal = await iContactRepository.GetAsync(id);
var updatedContact = Mapper.Map<ContactViewModel, Contact>(contactVm, contactOriginal);
updatedContact.Suppliers = supplierList;
await iContactRepository.UpdateAsync(updatedContact);
return Ok();
}
catch (Exception e)
{
throw new Exception("Could not update a contact", e);
}
}
Viewmodels:
public class ContactViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<SupplierViewModel> Suppliers { get; set; }
}
public class SupplierViewModel
{
public int Id { get; set; }
public string Name { get; set; }
}
Models:
public class Contact : IEntity<int>
{
public Contact()
{
Suppliers = new List<Supplier>();
}
[Key]
public int Id { get; set; }
public DateTime Created { get; set; }
public DateTime Updated { get; set; }
public string Name { get; set; }
public ICollection<Supplier> Suppliers { get; set; }
}
public class Supplier: IEntity<int>
{
public Supplier()
{
Contacts = new List<Contact>();
}
[Key]
public int Id { get; set; }
public DateTime Created { get; set; }
public DateTime Updated { get; set; }
public string Name { get; set; }
public virtual ICollection<Contact> Contacts { get; set; }
}
If you install the Unity bootstrapper for ASP.NET Web API package, a UnityHierarchicalDependencyResolver is available which will use a new child container for each IHttpController resolution effectively making all registrations with a HierarchicalLifetimeManager resolved per request so that all repository instances in a controller will use the same DbContext.
The NuGet package will also install some bootstrapping code in App_Start which uses WebActivatorEx. You can either use this approach or change to align with what you are using right now. Based on your posted code it would look something like:
public static void ConfigureUnity(HttpConfiguration config)
{
var container = new UnityContainer();
container.RegisterType<DbContext>(new HierarchicalLifetimeManager());
container.RegisterType<ISupplierRepository, SupplierRepository>();
container.RegisterType<IContactRepository, ContactRepository>();
config.DependencyResolver = new UnityHierarchicalDependencyResolver(container);
}
Solved it like this, dependency injection is from the tutorial Dependency Injection in ASP.NET Web API 2.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/dependency-injection
App_Start -> WebApiConfig
public static void Register(HttpConfiguration config)
{
UnityConfig.ConfigureUnity(config);
...
UnityConfig:
public static void ConfigureUnity(HttpConfiguration config)
{
var context = new DbContext();
var container = new UnityContainer();
container.RegisterType<ISupplierRepository, SupplierRepository>(new InjectionConstructor(context));
container.RegisterType<IContactRepository, ContactRepository>(new InjectionConstructor(context));
config.DependencyResolver = new UnityResolver(container);
}
Update: Use Randy Levy's answer instead.
My recommendation here is not to use Repository or UoW at all. EF already has them implemented. You'll encounter a lot of issues trying to re-implement them.
As to specific issue you encounter with exception: you have to use the same DbContext for your entities. At the same time, you wouldn't like to use DbContext as Singleton and use it per-request instead. A possible solution for it might be found here.
Application_BeginRequest(...)
{
var childContainer = _container.CreateChildContainer();
HttpContext.Items["container"] = childContainer;
childContainer.RegisterType<ObjectContext, MyContext>
(new ContainerControlledLifetimeManager());
}
Application_EndRequest(...)
{
var container = HttpContext.Items["container"] as IUnityContainer
if(container != null)
container.Dispose();
}
I'm creating a static class with static methods for helping the controllers to do their job. When build the application I get the following error:
Error 40 'System.Web.Mvc.Controller.Content(string)' is inaccessible due to its protection level"
Any idea how to solve this problem?
Notes:
It's a c# mvc aplication
public static ActionResult GetAlbumJSON(AlbumVO album)
{
return Controller.Content(
JsonConvert.SerializeObject(new
{
max_car = #ABookClient.maxCharsProjecName,
trans_img = #ABookClient.Transparent_Image,
show_description = #ABookClient.Show_Product_Description,
product_type = "Album",
obj = CreateObjAlbumVO(album),
})
);
}
Content method is protected internal, so you can't use it outside of controller.
Controller.Content Method. Most probably your static class violates SRP principle. Let him do his job (initializing, serializing,...) and controller - controller's job - return result to the client.
protected internal ContentResult Content(string content)
It would look smth like:
public static class MyHelper
{
public static object GetAlbum(AlbumVO album)
{
return new
{
max_car = #ABookClient.maxCharsProjecName,
trans_img = #ABookClient.Transparent_Image,
show_description = #ABookClient.Show_Product_Description,
product_type = "Album",
obj = CreateObjAlbumVO(album),
};
}
}
public class AlbumController : Controller
{
public ActionResult GetAlbums(int id)
{
var album = Context.GetAlbum(id);
var convertedResult = MyHelper.GetAlbum(album);
return Json(convertedResult);
}
}
Also I'd advice to take a look at AutoMapper for creating client response objects
I think this is valid case for a view-model for a JSON result since you do want a separation between the Domain model and the data sent back to the client. Using a view model also gives you a proper place to put this mapping between the domain model and the view (the JSON) so you don't need to delegate to a helper class.
public class AlbumModel
{
[JsonProperty(PropertyName = "max_car")]
public int MaxChars { get; private set; }
[JsonProperty(PropertyName = "trans_img")]
public string TransparentImage { get; private set; }
[JsonProperty(PropertyName = "product_type")]
public string ProductType { get; private set; }
[JsonProperty(PropertyName = "obj")]
public AlbumInfo Object { get; private set; }
[JsonProperty(PropertyName = "show_description")]
public bool ShowProductDescription { get; private set; }
public AlbumModel(AlbumVO album)
{
MaxChars = album.maxCharsProjecName;
TransparentImage = album.Transparent_Image;
ShowProductDescription = album.Show_Product_Description;
ProductType = "Album";
Object = new AlbumInfo(album);
}
}
The AlbumInfo class provides additional mappings for your JSON result, which becomes the "obj" property sent back to the client.
public class AlbumInfo
{
// ... define properties here
public AlbumInfo(AlbumVO album)
{
// ... map properties here
}
}
And your controller becomes nice and clean:
public class AlbumController : Conrtoller
{
public ActionResult GetAlbums(int id)
{
var album = Context.GetAlbum(id);
var model = new AlbumModel(album);
return Json(model);
}
}
I have a class course like this:
public class course
{
public int CourseID { get; set; }
public string Name { get; set; }
public Event Schedule {get; set;} //Event is coming from library Dday.iCal
}
Entity framework cannot correctly understand on how to save this property. ( I want to serialize it to string when saving, and keep it as event when worknig with it in my application.) So I have two methods, say, SerializeToString() and DeserializeFromString(). I want those methods to be applied only when saving to database.
What I came up with the following. Basically I'm trying to have a separate property as a string that will be saved in the database and Event will be ignored, but it doesn't save anything to the database now. I'm not even sure if this is a good approach to do things, or there's something better that can be done.:
public class course
{
public int CourseID { get; set; }
public string Name { get; set; }
private Event _Schedule;
[NotMapped]
public Event Schedule {
get
{
if (!String.IsNullOrEmpty(CourseSchedule))
{
return DeserilizeFromString(CourseSchedule);
}
return new Event();
}
set
{
_schedule = value;
}
}
private string _courseSchedule;
public string CourseSchedule {
get
{
return _courseSchedule;
}
private set
{
if (Schedule != null)
{
_courseSchedule = SerializeToString(Schedule);
}
else
{
_courseSchedule = null;
}
}
}
An author on asp.net actually has an implementation of what your trying to do, almost to a tee. You may want to follow a few points in that project to get you started. The link to the project is here.
Some things to note, is it does utilize the DbContext Api that was implemented in Entity Framework. Some of the abstraction mentioned above is like this:
Your Solution:
Model
View
Controller
Data Access Layer (DAL)
The tutorial will actually go through the implementation with a Course Controller, Unit Of Work Class, and Repositories. By the end of the tutorial it will implement those automatic properties with DbContext and looks like this:
// Model:
public abstract class Person
{
[Key]
public int PersonID { get; set; }
[Required(ErrorMessage = "Last name is required.")]
[Display(Name = "Last Name")]
[MaxLength(50)]
public string LastName { get; set; }
[Required(ErrorMessage = "First name is required.")]
[Column("FirstName")]
[Display(Name = "First Name")]
[MaxLength(50)]
public string FirstMidName { get; set; }
public string FullName
{
get
{
return LastName + ", " + FirstMidName;
}
}
}
// Repository:
public class StudentRepository : IStudentRepository, IDisposable
{
private SchoolContext context;
public StudentRepository(SchoolContext context)
{
this.context = context;
}
public IEnumerable<Student> GetStudents()
{
return context.Students.ToList();
}
public Student GetStudentByID(int id)
{
return context.Students.Find(id);
}
public void InsertStudent(Student student)
{
context.Students.Add(student);
}
public void DeleteStudent(int studentID)
{
Student student = context.Students.Find(studentID);
context.Students.Remove(student);
}
public void UpdateStudent(Student student)
{
context.Entry(student).State = EntityState.Modified;
}
public void Save()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
// Interface for Repository:
public interface IStudentRepository : IDisposable
{
IEnumerable<Student> GetStudents();
Student GetStudentByID(int studentId);
void InsertStudent(Student student);
void DeleteStudent(int studentID);
void UpdateStudent(Student student);
void Save();
}
// Context to Generate Database:
public class SchoolContext : DbContext
{
public DbSet<Course> Courses { get; set; }
public DbSet<Department> Departments { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Instructor> Instructors { get; set; }
public DbSet<Student> Students { get; set; }
public DbSet<Person> People { get; set; }
public DbSet<OfficeAssignment> OfficeAssignments { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Instructor>()
.HasOptional(p => p.OfficeAssignment).WithRequired(p => p.Instructor);
modelBuilder.Entity<Course>()
.HasMany(c => c.Instructors).WithMany(i => i.Courses)
.Map(t => t.MapLeftKey("CourseID")
.MapRightKey("PersonID")
.ToTable("CourseInstructor"));
modelBuilder.Entity<Department>()
.HasOptional(x => x.Administrator);
}
}
// Unit Of Work
public class UnitOfWork : IDisposable
{
private SchoolContext context = new SchoolContext();
private GenericRepository<Department> departmentRepository;
private CourseRepository courseRepository;
public GenericRepository<Department> DepartmentRepository
{
get
{
if (this.departmentRepository == null)
{
this.departmentRepository = new GenericRepository<Department>(context);
}
return departmentRepository;
}
}
public CourseRepository CourseRepository
{
get
{
if (this.courseRepository == null)
{
this.courseRepository = new CourseRepository(context);
}
return courseRepository;
}
}
public void Save()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
That is some of the content in the lesson, I believe it will answer your question pretty explicitly while giving you an understanding of why the abstraction works, since it does implement the Fluent Api.
Hope that helps.
You should keep your models as minimalistic as possible, just the auto-properties and attributes. For more complex business logic it's good to add another layer to your MVC pattern. This one is usually called Repository (hard to find a good tutorial on Repository Pattern though.. :( )and comes between model and controller controller.
This also is very useful for performing unit tests. When properly implemented it allows you to do replace database dependency with collection during tests. This approach will require a bunch of additional work on the project.
One more approach (a simpler one) would be to add a ViewModel layer. Do it this way:
class MyModel
{
public string Text { get; set; }
}
class MyViewModel : MyModel
{
public new string Text
{
get { return base.Text; }
set { base.Text =value.ToUpper(); }
}
}
class Program
{
static void Main(string[] args)
{
MyViewModel mvm = new MyViewModel();
mvm.Text = "hello there";
var s = ((MyModel) mvm).Text; // "HELLO THERE"
}
}
In DataContext use MyModel in controller use MyViewModel.
If you have a model that looks like this
using (LolEntities context = new LolEntities)
{
...
}
Somewhere in your application, this model is defined, usually something like this:
public partial class LolEntities : ObjectContext
(1) Notice that the class is partial, so you could just create another partial class with the same name and override:
public override int SaveChanges(SaveOptions options)
(2) Or you can just capture the event:
using (DemoAZ_8_0Entities context = new DemoAZ_8_0Entities())
{
context.SavingChanges += ...
}
and do your formatting before it gets sent back to the DB.
In your model just make sure to include a property that properly maps to the column in the DB.
Maybe introducing some abstraction over this logic, you could recreate the unit of work and repository pattern and add the desired logic in a more convenient way. For example in the Course repository class you can costumize the add and find method serializing and deserializing the event field.
I am going to focus on the repository pattern, you can find a lot of information about
the design of the whole data access layer on the web.
For example, to manage courses, your application should depends on a ICourseRepository interface like this
interface ICourseRepository
{
void Add(Course newCourse);
Course FindByID(int id);
}
And you provide the folowing implementation:
class CourseRepository
{
// DbContext and maybe other fields
public void Add(Course c)
{
// Serialize the event field before save the object
_courses.Add(c); // calling entity framework functions, note
// that '_courses' variable could be an DBSet from EF
}
public Course FindById(int id)
{
var course = /// utilize EF functions here to retrieve the object
// In course variable deserialize the event field before to return it ...
}
}
Note that the ObjectContext in EF is an implementation of this pattern, if you are not intresting in change the ORM in the future you can just override the Save method on EF.
If you want to know more about this kind of pattern you can visit the Martin Fowler site:
Unit Of Work pattern
Repository pattern