Got a bit of an issue with MVC and using Entity Framework POCO classes.
I've used database first in a separate project to represent my domain layer which has been referenced by my MVC project as the MVC side of things only represents a small UI portion of a larger solution.
Issue being is that the UI is not a true representation of my domain layer, so I've been creating ViewModel classes that bridge together UI objects with domain objects. I use translation methods in between to convert domain objects in the controller into the relevant UI object.
To me this seems a bit of a long winded process and is quite error prone as when an update is made the the UI, or database you have to reflect it in the UI object and vice versa, and the translate methods get increasingly complex as the UI grows.
Would this be the right approach? Is there an alternative mapper for these kinds of objects?
Domain Object
public class Ticket
{
public int Id { get; set; }
public int ClientRef { get; set; }
public int PriorityRef { get; set; }
public int CategoryRef { get; set; }
public DateTime CreatedDate { get; set; }
}
View Model Object
public class TicketViewModel
{
public int Id { get; set; }
public int ClientRef { get; set; }
public int PriorityRef { get; set; }
public int CategoryRef { get; set; }
public DateTime CreatedDate { get; set; }
public SelectList PrioritySelectList { get; set; }
public SelectList CategorySelectList { get; set; }
public static TicketViewModel Translate(Ticket ticket)
{
return new TicketViewModel
{
Id = ticket.Id,
ClientRef = ticket.ClientRef,
PriorityRef = ticket.PriorityRef,
CategoryRef = ticket.CategoryRef,
CreatedDate = ticket.CreatedDate,
PrioritySelectList = GetPrioritySelectList(),
CategorySelectList = GetCategorySelectList()
}
}
}
I wouldn't worry about it too much to be honest.
I also agree that this is the way to go. If you want to be as safe as possible when changes happen, just make sure that you only have to change one layer and that's the translation layer.
The UI never or seldom changes, because it is a right pain in the proverbial to have to go and change every single view when any data bit changes. So, anything changes in the DB, like a field renamed for example or even newly added, you deal with it on the translation layer.
The UI will never be a 100% mirror of your business layer and that's totally fine.
Related
In domain driven design we create bounded contexts. Which means that aggregates don't share a common model.
This image from Microsoft shows how aggregates communicate using commands and events (source).
Assuming those aggregates are at least two different microservices coded in different repositories. How should they share the scheme definition for the commands and events they communicate with? In my case those applications are .net core applications, so serialization and deserialization compatible with .net would be appreciated.
Also, maybe I'm missing some point as I'm new to domain events and communication works different, then I would like to know, what I'm not seeing.
Each service can have an internal model and you can use a Canonical Data Model for the communication between the services.
It's common to have a separate model used for integration that the internal model a service uses.
You can also check all the patterns in enterpriseintegrationpatterns.com and get the book. It's highly recommended.
Edit:
Here's an example with the order system. I'll skip some of the data that the objects will have to simplify the example and try to concentrate on the important parts i.e. the CDM and the internal model.
NOTE For a simple example, it's always difficult to justify some of the decisions as most of the things will be a lot simpler with the additional stuff. The implementation is done this way to help with the example.
Before I continue: Having a CDN will have some overhead in translation from the internal to the external model. If you think you can go without it, do so. Do not make things more complex than they need to be. The problem here is that if you need to change a command or event, this will propagate to all services and will cause a huge ripple effect in your system. The Domain-Driven Design book has a section on the Anti-Corruption Layer. Do check it out.
Why do we use a CDM? For Encapsulation. The same way an object encapsulates its data, the service encapsulates its internals. The CDM is intended to be used only for the communication/integration between the services and is intended to be shared between them.
Sharing the Internal Model of a Service with other Services is a bad thing because it will lock the developers from changing this Internal Model. Also sometimes details from one service can leak to other services and can cause huge problems.
Sharing a Special Data Model designed only for the communication between services is a good thing because it enforces a well-defined model for the communication and your system won't become a mess of events and commands with unknown schemas where every Service posts and consumes whatever it likes. I've seen those kinds of horrors, trust me you don't want that!
This model should be designed at a higher level of abstraction: The system level, having it's processes and flows in mind. It should be void of any details about the internals of the individual services.
What you need is Translation between the internal and external models. Also, you can use ContentFilter and ContentEnricher if you need to filter incoming events or commands and add more data to outgoing events or commands.
// Canonical Data Model
namespace CDM {
public interface ICommand { }
public interface IEvent { }
public class CustomerInfo {
public Guid Id { get; set; }
// notice here the CDM uses the two separate properties for the first and last name
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class LineItemData {
public Guid ProductId { get; set; }
public Quantity Quantity { get; set; }
public Money ListPrice { get; set; }
}
public class PlaceOrderCommand : ICommand {
public CustomerInfo CustomerInfo { get; set; }
public IReadOnlyList<LineItemData> LineItems { get; set; }
}
public class OrderPlacedEvent : IEvent {
public Guid OrderId { get; set; }
public IReadOnlyList<LineItemData> LineItems { get; set; }
}
} // end Canonical Data Model namespace
// Order Service Internals
// the name is done this way to differentiate between the CDM
// and the internal command, do not use it this way into production
public class LineItem {
// the internal one includes the OrderId { get; set; }
public Guid OrderId { get; set; }
public Guid ProductId { get; set; }
public Quantity Quantity { get; set; }
public Money ListPrice { get; set; }
}
public class PlaceOrderInternalCommand {
public Guid CustomerId { get; set; }
public string CustomerFullName { get; set; } // a single full name here
public IReadOnlyList<LineItemData> LineItems { get; set; }
}
public class Event { }
public class OrderPlacedInternalEvent : Event {
public Guid OrderId { get; set; }
public IReadOnlyList<LineItem> { get; set; }
}
// this is part of the infrastructure, received messages and translates/transforms
//them from the external CDM to the internal model.
// This is the input/receiving part of the service
public class CommandDispatcher {
public void Dispatch(ICommand cmd) {
// here we will use a MessageTranslator, check PatternsUsed section
var translator = TranlatorsRegistry.GetFor(cmd);
var internalCommand = translator.Translate(cmd);
Dispatch(internalCommand);
}
}
public class CommandHandler {
public void Handle(PlaceOrderInternlCommand cmd) {
// this will create the OrderCreated event
var order = CreateOrder(cmd);
// this will save the OrderCreated event
OrderRepository.Save(order);
}
}
// Another part of the infrastructure that publishes events.
// This is the output/sending part of the service
public class EventPublisher {
public void Publish(Event event) {
// another usage of the MessageTranslator pattern, this time on events
var translator = EventTranslatorRegisty.GetFor(event);
var cdmEvent = translator.Translate(event);
// publish to kafka or whatever you are using
PubilshToMessageMiddleware(cdmEvent);
}
}
Patterns Used:
Canonical Data Model
MessageTranslator
CommandMessage
EventMessage
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.
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.
I have an application that I'm trying to build with at least a nominally DDD-type domain model, and am struggling with a certain piece.
My entity has some business logic that uses some financial calculations and rate calculations that I currently have inside some domain services, as well as some constant values I'm putting in a value object.
I'm struggling with how to have the entity use the logic inside the domain services, or whether the logic inside those services even belongs there. This is what I have so far:
public class Ticket
{
public Ticket(int id, ConstantRates constantRates, FinancialCalculationService f, RateCalculationService r)
{
Id = id;
ConstantRates = constantRates;
FinancialCalculator = f;
RateCalculator = r;
}
private FinancialCalculationService FinancialCalculator { get; set; }
private RateCalculationService RateCalculator { get; set; }
private ConstantRates ConstantRates { get; set; }
public int Id { get; private set; }
public double ProjectedCosts { get; set; }
public double ProjectedBenefits { get; set; }
public double CalculateFinancialGain()
{
var discountRate = RateCalculator.CalculateDiscountRate(ConstantRates.Rate1, ConstantRates.Rate2,
ConstantRates.Rate3);
return FinancialCalculator.CalculateNetPresentValue(discountRate,
new[] {ProjectedCosts*-1, ProjectedBenefits});
}
}
public class ConstantRates
{
public double Rate1 { get; set; }
public double Rate2 { get; set; }
public double Rate3 { get; set; }
}
public class RateCalculationService
{
public double CalculateDiscountRate(double rate1, double rate2, double rate3 )
{
//do some jibba jabba
return 8.0;
}
}
public class FinancialCalculationService
{
public double CalculateNetPresentValue(double rate, params double[] values)
{
return Microsoft.VisualBasic.Financial.NPV(rate, ref values);
}
}
I feel like some of that calculation logic does belong in those domain services, but don't really like that I'll have to manually inject those dependencies from my Repository. Is there an alternate way that this should be modeled? Am I wrong in not liking that?
Having read the Blue Book but not really built anything in this style before, I'm looking for guidance.
EDIT
Thanks all for the feedback! Based on what I'm hearing, it sounds like my model should look more like the following. This look better?
public class Ticket
{
public Ticket(int id)
{
Id = id;
}
private ConstantRates ConstantRates { get; set; }
public int Id { get; private set; }
public double ProjectedCosts { get; set; }
public double ProjectedBenefits { get; set; }
public double FinancialGain { get; set; }
}
public class ConstantRates
{
public double Rate1 { get; set; }
public double Rate2 { get; set; }
public double Rate3 { get; set; }
}
public class FinancialGainCalculationService
{
public FinancialGainCalculationService(RateCalculationService rateCalculator,
FinancialCalculationService financialCalculator,
ConstantRateFactory rateFactory)
{
RateCalculator = rateCalculator;
FinancialCalculator = financialCalculator;
RateFactory = rateFactory;
}
private RateCalculationService RateCalculator { get; set; }
private FinancialCalculationService FinancialCalculator { get; set; }
private ConstantRateFactory RateFactory { get; set; }
public void CalculateFinancialGainFor(Ticket ticket)
{
var constantRates = RateFactory.Create();
var discountRate = RateCalculator.CalculateDiscountRate(constantRates.Rate1, constantRates.Rate2,
constantRates.Rate3);
ticket.FinancialGain = FinancialCalculator.CalculateNetPresentValue(discountRate,
new[] {ticket.ProjectedCosts*-1, ticket.ProjectedBenefits});
}
}
public class ConstantRateFactory
{
public ConstantRates Create()
{
return new ConstantRates();
}
}
public class RateCalculationService
{
public double CalculateDiscountRate(double rate1, double rate2, double rate3 )
{
//do some jibba jabba
return 8.0;
}
}
public class FinancialCalculationService
{
public double CalculateNetPresentValue(double rate, params double[] values)
{
return Microsoft.VisualBasic.Financial.NPV(rate, ref values);
}
}
The domain model ends up being fairly anemic at this point, but as I add features maybe it'll have more to it.
EDIT 2
Okay, I got some more feedback that perhaps my 'calculation' services are more like strategy objects that it's okay for my Entity to depend on. Here's another take at it with more of the logic back in the Entity, and making use of those strategy objects. Thoughts on this? Any issues with instantiating those helpers directly in the Entity? I don't think I'll want to mock those out in my tests, but OTOH I can't test the CalculateFinancialGain method without testing those strategy objects, either.
public class Ticket
{
public Ticket(int id, ConstantRates constantRates)
{
Id = id;
ConstantRates = constantRates;
}
private ConstantRates ConstantRates { get; set; }
public int Id { get; private set; }
public double ProjectedCosts { get; set; }
public double ProjectedBenefits { get; set; }
public double CalculateFinancialGain()
{
var rateCalculator = new RateCalculator();
var financeCalculator = new FinanceCalculator();
var discountRate = rateCalculator.CalculateDiscountRate(ConstantRates.Rate1, ConstantRates.Rate2,
ConstantRates.Rate3);
return financeCalculator.CalculateNetPresentValue(discountRate,
ProjectedCosts*-1,
ProjectedBenefits);
}
}
public class ConstantRates
{
public double Rate1 { get; set; }
public double Rate2 { get; set; }
public double Rate3 { get; set; }
}
public class RateCalculator
{
public double CalculateDiscountRate(double rate1, double rate2, double rate3 )
{
//do some jibba jabba
return 8.0;
}
}
public class FinanceCalculator
{
public double CalculateNetPresentValue(double rate, params double[] values)
{
return Microsoft.VisualBasic.Financial.NPV(rate, ref values);
}
}
Have your service accept the Ticket entity as a parameter. Services should be stateless and the same service should be able to provide its services to any number of entities.
In your situation I would pull the FinancialCalculatorService and RateCalculatorService out of your entity and make the methods on each service accept the Ticket entity as a parameter.
Take a second and read pg. 105 of Domain-Driven Design by Eric Evans
Given what we've seen of the classes, I don't think they're really services in the blue book sense, and I would keep the calculators in Ticket.
Neither FinancialCalculatorService or RateCalculationService has dependencies on domain entities - they both operate on primitive values. Applications shouldn't have to worry about how to calculate the financial gain that would result from a ticket, so it's valuable to encapsulate that information inside the ticket itself.
If they really don't have dependencies on domain entities, consider thinking of them as 'standalone classes' rather than 'services' (once again, in blue book terminology). It's certainly appropriate for Ticket depend on strategy objects (FinancialCalculator and RateCalculator) that do not themselves have exotic dependencies and do not themselves modify the state of domain entities.
Update for Edit 2. I think one of the advantages of making the calculators separate classes is that you can test them independently of Ticket. Strictly speaking, tickets aren't responsible for performing those calculations, they're responsible for making the right calls to those collaborating classes. So I'd be inclined to make them inject-able / mock-able as they were in your initial example.
i would say services use entities, not the other way around.
another thing, not sure on your domain, but are you certain ticket is an entity and not a value object?
You've actually struck on a question that there has been quite a bit of discussion on. There are believers on both sides of the tracks so you need to decide for yourself what makes the most sense.
Personally I don't have my entities use services as it creates a whole lot of work around the "How do I cleanly get services into my entities?" question.
It looks to me like CalculateFinancialGains() is more of a service level call. This does lead to Ticket being very anemic but I assume it has other behavior? And if it doesn't that's probably a smell...
This question is actually an example of a discussion that is in the book "Clean Code" (pp 96-97). The underlying question is whether or not to use a procedural approach or a object oriented approach. Hope I'm not in violation repeating a couple parts here, but here is what Bob Martin states for guidance:
Procedural code (code using data structures) makes it easy to add new functions without changing the existing data structures. OO code, on the other hand, makes it easy to add new classes without changing existing functions.
The compliment is also true:
Procedural code makes it hard to add new data structures because all the functions must change. OO code makes it hard to add new functions because all the classes must change.
My understanding that a DDD "Value type" would be what Bob Martin calls a data structure.
Hope this helps and doesn't just add to the noise :)
Let us say my domain object can contain a bunch of objects like this:
List<Thing> Things
where Thing is defined like this:
class Thing
(
public int ThingId { get; set; }
public string ThingName { get; set; }
)
My DTO contains
List<string> ThingIds;
List<string> ThingNames;
The question is how can I use automapper to map Things to the 'relevant bits' in the DTO?
Thanks.
Christian
By writing custom resolver, i guess.
That's quite unusual requirement - to lose binding between id and name.
I think you are right. sorry I am still learning about the dto/viewmodel mapping. Do you think it is acceptable to put a domain object inside a DTO as there is not much point in creating a dto for Thing?
Do not mix domain model inside view model. You will regret that next week (i did for sure...).
class Thing {
public int ThingId { get; set; }
public string ThingName { get; set; }
public string UnnecessaryProp {get;set;}
}
class ThingViewModel {
public int ThingId { get; set; }
public string ThingName { get; set; }
}
class MyView {
public IEnumerable<ThingViewModel> Things {get;set;}
}
Here You can find some more thoughts about view model.