OOP: use Entity Framework only in the data access layer - c#

My application has a business logic layer, and a data access layer. I want to give only the data access layer access to the database model. Now, I can easily do this, but then my UI classes cannot access the database classes like Reminder:
namespace Database
{
using System;
using System.Collections.Generic;
public partial class Reminder
{
public long Id { get; set; }
public string Name { get; set; }
public string Date { get; set; }
public string RepeatType { get; set; }
public string Note { get; set; }
public long Enabled { get; set; }
public string SoundFilePath { get; set; }
public string PostponeDate { get; set; }
public Nullable<long> EveryXCustom { get; set; }
public string RepeatDays { get; set; }
public Nullable<long> DayOfMonth { get; set; }
}
}
which is inside the database class library
I use this reminder class to store reminders. In my UI classes I use this class for various reasons.
To make use of this Reminder class, I simply add a reference to the class library that needs to use it. This works fine, but the problem is that every class library that references this, can alter the database like this.
If I'm not using Entity Framework, I could simply have a Reminder class outside the model (because there is no model) and load reminders from the database into that and extract them without using Entity Framework.
Here's an example of why I need to use the Reminder class in my UI classes (this is just a small code sample of one UI class)
This code is inside a timer that ticks every 30 seconds
// We will check for reminders here every 30 seconds.
foreach (Reminder rem in BLReminder.GetReminders())
{
// Create the popup. Do the other stuff afterwards.
if(rem.PostponeDate != null && Convert.ToDateTime(rem.PostponeDate) <= DateTime.Now && rem.Enabled == 1)
{
allowRefreshListview = true;
// temporarily disable it. When the user postpones the reminder, it will be re-enabled.
rem.Enabled = 0;
BLReminder.EditReminder(rem);
MakePopup(rem);
}
else if(Convert.ToDateTime(rem.Date.Split(',')[0]) <= DateTime.Now && rem.PostponeDate == null && rem.Enabled == 1)
{
allowRefreshListview = true;
// temporarily disable it. When the user postpones the reminder, it will be re-enabled.
rem.Enabled = 0;
BLReminder.EditReminder(rem);
MakePopup(rem);
}
}
GetReminders will do get the reminders from the database and put them in reminder objects
using (RemindMeDbEntities db = new RemindMeDbEntities())
{
localReminders = (from g in db.Reminder select g).ToList();
db.Dispose();
}

You can create separate project called i.e. Shared and put there all classes which are used in many projects. Then you need to reference this project by UI project and data access project (and by others which use these classes).
Both will have access to shared classes and UI won't be able to call data access layer directly.
You can also create interface outside of data access layer but if your classes are DTOs (Data Transfer Object) first option will be better.

If im not using the entity framework, i could simply have a reminder
class outside the model
You could create an interface instead of a class outside of the model in a shared assembly:
public interface IReminder
{
public long Id { get; }
public string Name { get; }
public string Date { get; }
public string RepeatType { get; }
public string Note { get; }
public long Enabled { get; }
public string SoundFilePath { get; }
public string PostponeDate { get; }
public Nullable<long> EveryXCustom { get; }
public string RepeatDays { get; }
public Nullable<long> DayOfMonth { get; }
}
Your Entity can than implement the interface:
public partial class Reminder : IReminder
{
//...
}
Maybe you want to make your Entities only internal visible and expose public service methods like IEnumerable<IReminder> GetReminders()

Related

Mvc core edit action not saving

So, I have this User Entity
using System;
using System.Collections.Generic;
using System.Text;
using Transport.Data.Entities;
namespace Transport.Data.Entities
{
public class User : BaseEntity
{
public String FirstName { get; set; }
public String LastName { get; set; }
public DateTime BirthDay { get; set; }
public String Email { get; set; }
public String UserName { get; set; }
public bool IsActive { get; set; }
public List<Viaje> Viaje { get; set; }
}
}
and here is the ViewModel for the Entity
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
using Transport.Data.Entities;
using Transport.Model.Infraestructure;
namespace Transport.Model.ViewModel
{
public class ViajeViewModel : BaseViewModel
{
public string Route { get; set; }
public string Destination { get; set; }
public string Origin { get; set; }
public int Price { get; set; }
public DateTime DepartureTime { get; set; }
public int UserId { get; set; }
[ForeignKey("UserId")]
public Viaje Viaje { get; set; }
public List<User> User { get; set; }
}
}
This is my Update Repository
DataResult IRepository<T>.Update(T entity)
{
DataResult result = new DataResult();
try
{
result.Data = entity;
context.SaveChanges();
result.Successfull = true;
}
catch (Exception ex)
{
result.LogError(ex);
result.Successfull = false;
}
return result;
}
And my update service
public ServiceResult Update(Vm viewModel)
{
ServiceResult serviceResult = new ServiceResult();
var ToUpdate = this.Repository.GetById((int)viewModel.Id).Data;
if (ToUpdate == null)
{
serviceResult.Success = false;
serviceResult.ResultTitle = "ERROR: Record No Found";
//serviceResult.Messages.Add(Error.GetErrorMessage(Error.RecordNotFound));
return serviceResult;
}
var Entity = MapperHelper.Instance.Map<Vm, Ent>(viewModel);
var result = this.Repository.Update(Entity);
serviceResult.Success = result.Successfull;
serviceResult.ResultTitle = (result.Successfull ? Error.GetErrorMessage(Error.CorrectTransaction) : Error.GetErrorMessage(Error.InternalServerError));
//serviceResult.Messages.Add(result.Successfull ? "Updated" : "Failed");
serviceResult.ResultObject = MapperHelper.
Instance.Map<Ent, Vm>(result.Data);
this.Repository.SaveChanges();
return serviceResult;
}
This is my update user controller
[HttpPost("users/edit/{id}")]
public ActionResult UserEdit(UserViewModel userViewModel)
{
var users = userService.Update(userViewModel).ResultObject;
return RedirectToAction("Index", "Users");
}
The repository and service are doing their jobs looking for an user by an id and updating their values but when the UserEdit Controller it's done my changes are not being saved in the database.
Can anyone give me some advice to resolve this problem ?
EF relies on internal entity change tracking to determine what operations it needs to perform in the database. All your Update method does is call SaveChanges, so simply changes being made to the entity are not being tracked for some reason, and when you call SaveChanges, EF sees no work it needs to do, and just returns. As to why your entity changes aren't being tracked, there's not enough of your repository here to tell.
However, I will say that this is one of the paramount reasons to not use the repository pattern with EF. It's far too easy to do stuff that borks EF's change tracking, and 99 times out of 100, that's exactly what developers do. When you use an ORM like EF, that is your data layer. It implements the repository and unit of work patterns already. Not every "layer" in your architecture has to actually be owned by you, and this is a critical mistake far too many developers make. Just use your context directly. That's what it's for.
Now, purists might argue that you'll have a hard dependency on EF. Well, guess what? You do regardless. You've chosen it as an ORM, and that decision doesn't and shouldn't come lightly. What if you want to switch it out with something else down the line? That question always gets raised as well. Simply, you won't. The friction involved in switching out something like an ORM is such that it will never be a business priority.
Nevertheless, if you want to truly abstract the dependency, you should be looking at patterns like CQRS or microservices, which unlike a redundant and useless repository layer, actually do add value to your application. However, those patterns are complex to implement and overkill for most applications.

Mapping Business Object to multiple Database Tables

I am migrating /re-developing a web app from JavaScript to the ASP.NET MVC Framework using C#/ JS (with Handlebars.NET) for my Bachelor thesis.
So far I have created a Web.API and the actual app with a form.
In the app I enter details to create a new Employee, which is then Posted to the API, which receives that Json-Object as a "Business Object" BOEmployee.
Said BOEmployee looks like this (simplified):
public class BOEmployee
{
public int ID_Employee { get; set; }
public int ID_Company { get; set; }
public string lastName { get; set; }
public string firstName { get; set; }
}
I want to map this object to two other objects, representing tables of the underlying database, to then save them to the database. The two target tables are auto generated with Entity Framework.
Here are the table objects:
1. Employee:
public partial class Employee
{
public int ID_Employee { get; set; }
public int ID_Company { get; set; }
}
2. Employee_Details:
public partial class Employee_Detail
{
public int ID_Employee_Detail { get; set; }
public int ID_Employee { get; set; }
public string lastName { get; set; }
public string firstName { get; set; }
}
Now I could map them manually by assigning every attribute but clearly that is a horribly unsustainable idea. So I was looking for a way to automate that mapping process automatically using Json.Net like this:
[HttpPost]
public BOEmployee SaveEmployee([FromBody] string employee)
{
using (var context = new myDBEntities())
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
Employee_Detail dbEmployeeDetails = serializer.Deserialize<Employee_Detail>(BOEmployee);
Employee dbEmployee = serializer.Deserialize<Employee>(BOemployee);
}
}
Now what happens when I run that code is, that the serializer-function complains that the input values cannot be null, which to my understanding is because the target Objects (e.g. Employee) do not have all attributes that are given in the serialized Json-Object.
The Error Message is this:
Value cannot be null.\r\nParameter name: input",
"ExceptionType":"System.ArgumentNullException"
Now my question would be, how can I map my object to the different Database tables? Or am I completely on the wrong path now?
Fundamental changes to the program structure cannot be made any more due to available time (and I am basically a complete beginner in programming).
I recommend AutoMapper than what you are using there.

C# (Web API) Multilayer (IOC) API Controller Return Type

I am building an ASP Web API application and this time I thought I will go with the MVC pattern. I got along with most of the stuff, but there is one thing of which I am unsure. First of all my project consists of the following:
Data Layer
Business Layer
Model Layer (just the model with the properties)
Service Application (here are my controllers)
every one of them in a separate project
Lets say I have the following controller
public class TestController : ApiController
{
ISomeService _someBusiness;
public TestController(ISomeService someBusiness)
{
_someBusiness = someBusiness;
}
public **SomeModelObject** GetModelObject(ind id)
{
return _someBusiness .GetSomeModelObject(id);
}
}
Now my problem is the return value of GetModelObject(int id). Here it says SomeModelObject. That implies that my Service application (or my controller) has to know everything about the model which is being used (so I dont see the point in defining it in a separate .dll). One way would be to define the model (precisely the get/set mothods) as an interface, but I think that it would be too much that every model class has an interface (mostly because, as I said, just the properties are being stored inside the model), and despite that I just does not feel right to build an interface for a class which only stores data. So, is there any generic response type which is being used in this case (even some completely different approach), or do I have to use my model classes (or may i just always use string and it is being converted to the appropriate format by the client) ?
There's a good reason to use an interface to hide the complexity of the model object. It holds data, sure. But it holds unnecessary data that is only meaningful to the data layer. Take this EF model:
public class Employee
{
public int Id { get; set; }
public string EmployeeNumber { get; set; }
public string Name { get; set; }
public virtual Collection<TimeCard> TimeCards { get; set; }
public int DepartmentId { get; set; }
public virtual Department Department { get; set; }
}
This is a fairy common EF model. It contains a surrogate key Id, and a foreign key DepartmentId. Those values are meaningless except for the database and, by extension, for entity framework. EmployeeNumber is the natural key which uniquely identifies the entity in the user's domain.
Outside of database access, you should really only deal with natural data values. You could do this by declaring yet another data-carrying class in the Business layer and perform mapping, or a better idea is to use an interface to hide all of the members that are not useful.
public interface IEmployee
{
string EmployeeNumber { get; }
string Name { get; set; }
ICollection<ITimeCard> TimeCards { get; }
IDepartment Department { get; set; }
}
Notice the lack of some setters in the interface. You'll never want to change the EmployeeNumber because that is the natural key for the entity. Likewise, you'll never assign a collection object to the TimeCards property. You'll only ever iterate over, add, or remove them.
Now your Employee class becomes
public class Employee : IEmployee
{
public int Id { get; set; }
public string EmployeeNumber { get; set; }
public string Name { get; set; }
public virtual Collection<TimeCard> TimeCards { get; set; }
ICollection<ITimeCard> IEmployee.TimeCards { get { return TimeCards; } }
public int DepartmentId { get; set; }
public virtual Department Department { get; set; }
IDepartment IEmployee.Department { get { return Department; } set { Department = value; } }
}
In your business layer and above, you'll only use variable of IEmployee, IDepartment, and ITimeCard. So you are exposing a tighter API to the higher layers, which is a good thing.
You could try to use a generic approach at controller level:
public class BusinessController<T> : ApiController
{
ISomeService _someBusiness;
public TestController(ISomeService someBusiness)
{
_someBusiness = someBusiness;
}
public T GetModelObject(ind id)
{
return _someBusiness.GetSomeModelObject(id);
}
}
Finally your controlers inherit from BusinessController instead of ApiController:
public class TestController : BusinessController<SomeModelObject>
{
}
You could also take advance of the templating to inject the right "ISomeService" by using an IoC container and a bootstrapper.

Entity Framework child with multiple Parent Types

I have 3 classes inheriting from OwnableSpaceObject that has 2 navigation properties to their children via ICollections.
From the OwnableSpaceObject I want to be able to have a class like AddChild which will add one of the child classes to the ICollection and save it to the database.
Here is the OwnableSpaceObject base class:
public abstract class OwnableSpaceObject : SpaceObject
{
public int? UserId { get; set; }
public int? ResourcesId { get; set; }
[ForeignKey("UserId")]
public virtual UserProfile User { get; set; }
[ForeignKey("ResourcesId")]
public virtual Resources Resources { get; set; }
public virtual ICollection<Structure> Structures { get; set; }
public virtual ICollection<Ship> Ships { get; set; }
}
Here is the method I'm trying to use:
public Structure CheckOrAddChild(StructureType _structureType)
{
using (ChronosContext db = new ChronosContext())
{
var structure = Structures != null ? Structures.FirstOrDefault(x => x.StructureTypeId == _structureType.Id) : null;
if (structure == null)
{
Structure newStructure = new Structure(_structureType.Id);
Structures.Add(newStructure); //this should add the Ship to the database and link it to the parent OwnableSpaceObject right? It errors out right here saying that Structures is null
db.SaveChanges();
structure = newStructure;
}
return structure;
}
}
And similarly an overloaded CheckOrAddChild for adding Ships:
public virtual Ship CheckOrAddChild(ShipType _shipType)
{
using (ChronosContext db = new ChronosContext())
{
var ship = Ships != null ? Ships.FirstOrDefault(x => x.ShipTypeId == _shipType.Id) : null;
if (ship == null)
{
Ship newShip = new Ship(_shipType.Id);
Ships.Add(newShip); //this should add the Ship to the database and link it to the parent OwnableSpaceObject right? It errors out right here saying that Ships is null
db.SaveChanges();
ship = newShip;
}
return ship;
}
}
Here is basically what the Ships and Structures class looks like:
public class Ship
{
public int Id { get; set; }
public int CurrentAmount { get; set; }
public int BuildingAmount { get; set; }
public int ShipTypeId { get; set; }
[ForeignKey("ShipTypeId")]
public virtual ShipType ShipType { get; set; }
}
The Ship/Structure class does not have a navigation property to OwnableSpaceObject because it then crate one huge table for all of my Fleets/Asteroids/Planets because they all inherit from OwnableSpaceObject. I want to keep Fleets/Asteroids/Planets separate in the tables but be able to still attach Ships and Structures to them. Currently EF is making 3 columns in the Ships/Structures tables named "Asteroid_Id", "Planet_Id", and "Fleet_Id" respectively. Should I just make a navigation property for each of these and manually link them up myself? I was trying to avoid this in order to avoid repetitive code.
Anyone have any ideas for this? I've been researching for the past 2 days and I'm about to have a nervous breakdown!

Facade a class without writing lots of boilerplate code?

Let's say I have a class from a 3rd-party, which is a data-model. It has perhaps 100 properties (some with public setters and getters, others with public getters but private setters). Let's call this class ContosoEmployeeModel
I want to facade this class with an interface (INavigationItem, which has Name and DBID properties) to allow it to be used in my application (it's a PowerShell provider, but that's not important right now). However, it also needs to be usable as a ContosoEmployeeModel.
My initial implementation looked like this:
public class ContosoEmployeeModel
{
// Note this class is not under my control. I'm supplied
// an instance of it that I have to work with.
public DateTime EmployeeDateOfBirth { get; set; }
// and 99 other properties.
}
public class FacadedEmployeeModel : ContosoEmployeeModel, INavigationItem
{
private ContosoEmployeeModel model;
public FacadedEmployeeModel(ContosoEmployeeModel model)
{
this.model = model;
}
// INavigationItem properties
string INavigationItem.Name { get; set;}
int INavigationItem.DBID { get; set;}
// ContosoEmployeeModel properties
public DateTime EmployeeDateOfBirth
{
get { return this.model.EmployeeDateOfBirth; }
set { this.model.EmployeeDateOfBirth = value; }
}
// And now write 99 more properties that look like this :-(
}
However, it's clear that this will involve writing a huge amount of boilerplate code to expose all the properties , and I'd rather avoid this if I can. I can T4 code-generate this code in a partial class, and will do if there aren't any better ideas, but I though I'd ask here to see if anyone had any better ideas using some super wizzy bit of C# magic
Please note - the API I use to obtain the ContosoEmployeeModel can only return a ContosoEmployeeModel - I can't extend it to return a FacededEmployeeModel, so wrapping the model is the only solution I can think of - I'm happy to be corrected though :)
The other approach may be suitable for you is to use AutoMapper to map base class to your facade here is sample code:
class Program
{
static void Main(string[] args)
{
var model = new Model { Count = 123, Date = DateTime.Now, Name = "Some name" };
Mapper.CreateMap<Model, FacadeForModel>();
var mappedObject = AutoMapper.Mapper.Map<FacadeForModel>(model);
Console.WriteLine(mappedObject);
Console.ReadLine();
}
class Model
{
public string Name { get; set; }
public DateTime Date { get; set; }
public int Count { get; set; }
}
interface INavigationItem
{
int Id { get; set; }
string OtherProp { get; set; }
}
class FacadeForModel : Model, INavigationItem
{
public int Id { get; set; }
public string OtherProp { get; set; }
}
}
Resharper allows the creation of "delegating members", which copies the interface of a contained object onto the containing object and tunnels the method calls/property access through to the contained object.
http://www.jetbrains.com/resharper/webhelp/Code_Generation__Delegating_Members.html
Once you've done that, you can then extract an interface on your proxy class.

Categories

Resources