I have an EDM used to bring back a collection of "Product" entities within a DAL project. An MVC website project references and directly instantiates the ObjectContext and returns an IQueryable to the website for paging and displaying of Products.
This Entity, to simplify things, we'll say only has "ID", "Rate" and "Description" properties. I want to create another calculated property called "CostPerMonth" which will take an input from the website called "LoanAmount", and, again, to keep things simple, this "CostPerMonth" property will be made up of (("LoanAmount" * "Rate") / 12).
I can't help but feel this calculation should be done in the DAL project to make the code more reusable, as whereever this data is used, a "LoanAmount" will always be specified. The possible solutions I have had are below:
Create a partial class for Product, add a new property "CostPerMonth" to Product. In the website controller, when the data is returned, populate this new column by iterating through the returned data and doing the calculations?
Create a partial class for Product, add a new property "CostPerMonth" to Product. In the DAL project, create a helper class that has a method that accepts a "LoanAmount" parameter and returns a List. The trouble with this is I would need to materialize the data in order to do the calculations. The method could accept a "Skip" and "Take" parameter that could be used in the Linq query used to return the products?
Create a partial class for Product, add a new property "CostPerMonth" to Product. Add another tier to the solution using WCF web services, within the service method do the calculations and use REST to return the data to the MVC web site?
Any advice would be very much appreciated.
Best regards,
Mark
If we take a step back and actually breakdown what you are asking in your question it might be easier to explain my answer.
We have an object/entity named Products
There is a calculated field which will be (("LoanAmount" * "Rate") / 12)
CostPerMonth does not need to be stored in the database
So this calculated field is a business rule for the Product Entity. Given that you are using MVC, there is only one place where this code/logic can go and that is the model.
Given that your using EF It will sit in a non mapped/computed field and the code to give you an idea will look something like this....
[NotMapped]
public decimal CostPerMonth
{
get { return (LoanAmount * Rate)/12 ; }
}
I can go on for days about the problems about having fragmented business logic throughout various layers.
Now if you want your this logic to be consumed easily by other clients, you need to expose a service to do that. (you can use webAPI/service stack/ wcf, etc) it is really another entire question based on your needs. But the point here is that your logic is in one spot.
Related
I would like to learn more about the appropriate way to use classes when using a database. Here is the example of what I think is ok.(Using C# and SQL Server if curious)
I Have a table called "Features" and most of the columns in it hold IDs(Foreign keys). To load that table into the application, I create a "DBFeatures" class to hold all the columns. Next I should have a regular "Features" class that has the actual values of all properties in "DBFeatures" class. "Features" class would have a method that opens a connection to the database to grab all the right values with the given IDs. Then The "Features" class can be used as is.
The same would go in reverse, I create an object of "Features", then it converts it into a "DBFeatures" class which gets passed to the database when INSERTING.
Is this the right way to go about this? What other options would be better? The only other option is just have one class, "DBFeature" class, and when I create an object of that class, each time a property is set or gets, it would have to access the database to get the value by providing an ID.
EDIT
I'll be using the data for forms. Most of the tables will be read only which will be stored into a list of objects which can then be used with Controls(like the data source of a combobox). Also I want to be able to load user input into a class that would be outputed to a table in the database.
A lot of planning on how to do something depends on your implementation which you are not providing. What are you planning to do with your objects? Is it for a report? Do you need to manipulate the values?
I'm going to assume you are going to be manipulating the data in which case you should have a class that opens the database and loads it into classes that represent it.
The class can have properties that correspond to the columns and then you can have a list of the class to represent the rows.
This is just one example of how to do it but its impossible to say without knowing what your intent is and having more details.
It looks like you need ORM like Entity Framework.
What is a good way to handle/organize/use Hardcoded Types with an ASP.NET MVC application using Entity Framework?
By Hardcoded Types I mean static types defined in the business logic that will not be manageable by the User, only the developer. i.e. ProductTypes, CustomerStatuses, etc..
I am trying to achieve a couple of things:
Works well with Entity Framework data binding
Will be able to populate MVC View DropDownLists easily (assuming my ViewModel will be able to have a list of the type)
Will have a reliable valued stored in SQL (whether it is a string or Id)
Will be able to use in if/case statements throughout business logic
Using Enums:
For example lets say I have a Product entity which has a Type field.
My first instinct is to create an Enum directly in the class called ProductType with its values. However if I use enums throughout I am worried that I won't be able to accomplish the 4 above requirements.
Using GlobalConstants
In the past I have also created a GlobalConstants file and just created a bunch of constant strings so I could use them throughout the BusinessLogic. Then in the database I would create a TypeList table (TypeName, TypeValue, FriendlyName, etc..) that stores all of these values. So basically the TypeList table would always have to stay in sync with the GlobalConstants or something would break.
Something is telling me Enums is perfect for these hardcoded types
Just create a model for ProductType. Example:
ProductType: {int id, string name}
In the Product model class add:
public ProductType Type { get; set; }
So basically you can store the types in database.
I've searched both SO and Google on this but have not found a relevant / acceptable answer.
Background:
* Using MVC 4.5
* I have some Generic Repo<T> that I am using over the top of EF5, which in turn are accessed by generic Service<T>
* I have domain models and view models and I am using Automapper to map between them, this mapping happens in the Service layer
* On top of that, I have my Controllers which again are generic as much as possible.
So, to the question; I have a couple of scenarios where I need to present a list of options to the user and they have to select one or more. The options are user specific, so my domain User has a List<Location> which is their saved locations, and when adding / modifying, an Item, they are required to select at least one Location.
I am resisting the temptation to fetch that List<Location> in my controllers because I want to keep them generic and slim, but at the same time, I'd rather not have two properties in my ItemView model, one for AvailableLocations and one for SelectedLocations, because this model is used not just for adding / modifying but for search results etc.
Options:
* Should I introduce a different model for adding / modifying an Item, e.g. ItemInput?
* Should I use some custom mapping and get Automapper to get the list of available locations?
* In which layer should I fetch these available locations?
What are people's suggestions on a neat and generic approach to this please?
Many thanks!
I would do something like this:
public IEnumerable<Location> GetLocations() {
return db.GetAll();
}
Then inside of your controller (I followed this from MVC scaffolding):
ViewBag.Locations = new SelectList(service.GetLocations, "name", "id");
(or your own checkbox list)
and put a listing control on the HTML/View page.
The reason I believe this is the best method is because the logic all resides inside the service. If you put it in your DTO/data model you may come against this problem:
What happens if you require additional logic to pull back locations? i.e. sub locations of locations.
You change your service (or override) to reflect the new changes, and this logic would go inside of the service:
public IEnumerable<Location> GetLocations(string parent) {
return db.GetAll().Where(loc => loc.parentname = parent);
}
p.s. I never use generic services, the reason I have a service is because some of the data access it provides contains logic that is not meant to sit with the generic DAL.
I could make an interface or abstract service to make my life a little easier for common operations between services but once you define say a concrete, a UserManagementSerive surely you are saying you want to manage an object that has Users, and Locations and Items each having its own specific functionality?
I don't think there is only one possible answer to this question.
I would recommend a simple, but not-so-generic approach. I would write what's called ViewModels, i.e. model classes that are related to your specific views. Then I would get your available locations from the controller, and populate an instance of the ViewModel in your controller using the fetched locations.
Basically I would expose some services like:
IEnumerable<Location> GetAvailableLocationsForUser(string userName);
Do note I've used IEnumerable<T>, not IQueryable<T>. Because the implementation will actually request the database, as it's too much bug-prone (at least IMO) if it's the role of the controller to do so (remember the deferred execution of IQueryable<T>).
And it returns a domain instance, i.e. an entity, not a mapped model. I wouldn't personally deal with anything but domain classes in the service layer. There could be domain classes that are not entities, but compositions of entities for example. This could help making efficient requests and avoiding using lazy-loading and deferred execution in the controllers. This is helpful when the controller needs a whole object graph and not only an entity.
Then I would write Models and ViewModels like the following, in the web application assembly:
public LocationModel
{
...
}
public CreateItemViewModel : ItemModel
{
public List<LocationModel> AssociatedLocations { get; set; }
public List<LocationModel> AvailableLocations { get; set; }
...
}
There are basically Models (ItemModel and LocationModel), which are objects related to the web application. This means there could be some web-related things in those models, for example computed read-only properties or attributes on properties (DisplayAttribute...etc.).
I would write those models multiple times, actually, because I don't think this is something that could be generalized: for example, one view could require the use of a navigation property while another view wouldn't. So this changes the depth of the mapping process depending on the views that uses the model. And I wouldn't use AutoMapper at all (only hand-written mappers).
There are also ViewModels (CreateItemViewModel), which are objects related to a single view (for example the view that allows to create an Item in this example). The difference between Model and ViewModel is that the ViewModel is related to a single view (and named according to this view). On the other hand, Models are related to multiple views (its namespace would help to know which views. For example, xxx.Item.Models for Models related to all views in the xxx.Item directory). ViewModels are built from scratch in the controller (or in a separate mapper) based on the domain classes.
In the above example, you could build a domain classes that would return AssociatedLocations and AvailableLocations, but it would require your service layer to be aware of the web part (I mean, your service interface and domain classes would know which properties are needed for a particular view). I'm not sure those properties are actually related to a single view in your application, but if it's not the case, you could also build a domain class as a composition of entities that would return AssociatedLocations and AvailableLocations:
public ItemExtended : Item
{
public List<Location> AssociatedLocations { get; set; }
public List<Location> AvailableLocations { get; set; }
}
ItemExtended GetItemExtendedById(long idItem);
Suppose we have class PersonModel, user edits a detail form in the browser and hits the submit button.
How to write a controller logic to create an UPDATE SqlComand (no EF) and update only those of fields from class PersonModel (FirstName, LastName, Age...) which have been changed.
What should be an argument of the /Person/Edit/<id> controller?
You don't do anything special to your MVC code, and you don't add any special URL parameters.
If you only want to update the changed fields, then you have to write a lot of code. You have to get the current record, compare each of your models fields to the records fields, figure out which ones have changed, then you have to construct a SQL statement based on the changed fields, then update it, making sure to use optomistic record locking to insure the field has not changed between when you retrieved it and when you update it.
This is probably going to be a couple hundred lines of code. Or it could be one line of code if you were using an ORM.
Also, keep in mind you need to use parameterized statements as well, to insure against a SQL injection attack (something you get for free in an ORM as well).
Good luck, I certainly am not going to write it.
What I would suggest is that you don't use the generalized PersonModel which I assume is a 1:1 representation of your data model. You should create a watered down view model of with only the fields you care about. Then use something like AutoMapper to map the ViewModel back to your DomainModel.
Here is a reference on how to use AutoMapper for such a scenario.
How to cross map objects using AutoMapper
You may use Linq and let the datacontext do everything for you.
In the Model you just create your data class with the linq queries for the update, retrieve the object, set all the values that have been passed from the view in the object you've retrieved (you'll have to do this anyway, since the pattern decouples the view from the model | Remember too, that MVC implements observer for letting the view to know about changes in the model, so you can't know what was modified in the view from the controller), and then you call the DataContext.SubmitChanges(); method. The data context will do the job in its own. It will know what to change and modify and will make the most performant query.
I was wondering how to change input values when using the Entity Framework. Till now I'm using selfmade custom classes which I transform to entity classes. I think I'm doubling the work i have to do. In the custom class I transform the incomming value at the setter. Postal codes in the netherlands are 4 digits plus 2 characters. Some people seperate them with a space, others join them together. At this moment a Regex wil seperate the digits from the characters if necessary. When using the Entity Framework. Is there a possibility to change the incomming value before writing the value to te database? And if so how do I do so?
I was searching for validation but all examples I saw where only throwing errors without effectively transforming the value.
Example of Dutch Postal Code: "5126HG" or "5126 HG" should both result in the same result in the database. I already know how to change, but not where and how to apply.
I think that using custom classes is a good idea, it's similat to implement the DTO pattern and it's a good method to separate business layer from data access layer. But if you want to add some validation / modification methods to the entity classes you can do it.
If you are using EF 4.1 you have POCO classes for entities createted by the generator as partial classes. You can add your custom partial classes adding validation methods, but you need to explicitly call these methods before executing a db operation.
Another way is using a custom SaveChange handler. Here you can find an example of SaveChange customization.
http://msdn.microsoft.com/en-us/library/cc716714.aspx
Is there a possibility to change the incomming value before writing the value to te database? And if so how do I do so?
It is better to have some separate Controller class with a method that takes, validates, transforms inputs and only then sets Entity properties with valid, correct and consistent values.
This way your Entities are always valid and correct and you never ever need a nonstandard mechanism to change values before writing to the database.