In order to make my web-application project I used some tutorials and downloaded 2 sample projects. I noticed that in both of them entities were imported from the SQL server into the project AND models were created for each related class. From what I understand, the entities represent the database itself while the models are the ones to check validations (for example) and after validations successfully passed, the data is sent in to the entities which in turn get it into the database (?) .
In my project I have no models at all. I thought that the entities represent the models, therefore why shall I create duplicate classes (rather entities and models which both look alike).
All the data annotations are inside the entities classes.
I was told that each change done in the tables inside the SQL server would erase my entire work.
I would like to know whether it's true or not, as well as why do I acctually need models when I have entities instead.
If models ARE needed, how do you acctually pass their data into the entities?
Edit:
I found this post Difference between model and entity which answers most of my question.
I would like to know whether my entire entity class's annotations are erased whenever I change a simple thing in the SQL server.
Why wouldn't the model class be an exact duplicate of the entity class (besides the data annotations)?
The models represents the database entities. Those models shouldn't be responsible for displaying data in views or validating user input - their only usage is to represent some table in a database as a c# object.
Let say you have model:
[Table("Products", Schema = "product")]
public class Product
{
public long Id { get; set; }
public string Name { get; set; }
public long CategoryId { get; set; }
public string Description { get; set; }
public string ManufacturerUrl { get; set; }
public string ImageUrl { get; set; }
public decimal Price { get; set; }
public int Stock { get; set; }
public Category Category { get; set; }
}
Now to make use of it in your views and add some validation if you like then you should create a so called ViewModel for it which could be something like this:
public class ProductViewModel
{
public long Id { get; set; }
public string Name { get; set; }
public int CategoryId { get; set; }
[DataType(DataType.MultilineText)]
public string Description { get; set; }
[DataType(DataType.Url)]
[Display(Name = "Producer")]
public string ManufacturerUrl { get; set; }
[DataType(DataType.ImageUrl)]
public string ImageUrl { get; set; }
[DataType(DataType.Currency)]
public decimal Price { get; set; }
[Display(Name = "In stock")]
public int Stock { get; set; }
public CategoryViewModel Category { get; set; }
}
Suppose your entity is Person. You decide to have the Entity as the Model, instead of a different class.
In your view (editing an existing person), there is a dropdownlist with country names (Person needs a Country entity). So, that means that you need a list of all possible countries, so the user can select one.
How do you pass that list of countries?
Well, if you have a separate class that you use as the Model, you can easily add a new property, put the list of countries in that, and then get that from your view.
So your viewmodel for this example would be:
public class PersonEditModel
{
public Person PersonToEdit { get; set; } //This is your entity from before
public List<Country> Countries { get; set; } //Extra data for the view
}
Think of your model as a sort of 'package' that combines your entity with all other needed information that the view requires. In case there is no extra information required, you could forego the Model and keep using the Entity directly.
But most people label this bad practice. What if you need an extra bit of information suddenly? You'd have to rewrite your code to now start implementing a model.
Long story short: If you have no need for extra data in the view, and you're working on a private project; do whatever you think is best. Professionally, I would suggest always using a Model, if only to make sure you can add extra data in the future.
Because as you rightly pointed out, your entities will be erased and recreated if you ever refreshed your edmx file.
You could actually lose the model layer if you use partial classes and put your business rules in there, but the point of having a model layer is that it is much simpler to write unit tests for models than for entities.
I suggest that after you've finished learning the basics, you go on and learn about Domain Driven Development (DDD) and Test Driven Development(TDD). All you questions will be answered then, because if I bombard you with all of the theory now you'd probably get lost or think it's much more difficult than it actually is..
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
I'm always struggling with naming convention and design pattern for my application, it's been very hard to keep it consistent, so I have a simple case, let's say I have a service with method called CreateOrder
public OrderDTO CreateOrder(int customerID, OrderShipDTO shipping, OrderDetailDTO products);
Here's the DTO class
public class OrderDTO
{
public int ID { get; set; }
public decimal PriceTotal { get; set; }
public string Status { get; set; }
public string PaymentMethod { get; set; }
public OrderShipDTO OrderShip { get; set; }
public ICollection<OrderDetailDTO> OrderDetails { get; set; }
}
public class OrderShipDTO
{
public string Name { get; set; }
public string Phone { get; set; }
public string Address { get; set; }
public string Province { get; set; }
public string City { get; set; }
public string District { get; set; }
public string SubDistrict { get; set; }
public string ZipCode { get; set; }
}
public class OrderDetailDTO
{
public int ID { get; set; }
public decimal Quantity { get; set; }
public decimal Price { get; set; }
public int ProductID { get; set; }
}
As you can see, my method CreateOrder will return OrderDTO and accept OrderDetailDTO parameters, but the method actually only requires property OrderDetailDTO.ProductID and OrderDetailDTO.Quantity for the business logic calculation.
So, it feels not right for me (and confusing because I wasn't sure which properties need to have a value and which doesn't) to pass the entire OrderDetailDTO object even though it only needs 2 of the properties to be filled, but I still need to pass back the OrderDTO which will include ICollection<OrderDetailDTO> because I need to get the OrderDetailDTO.Price value and show it to my customer.
So I was thinking of creating another DTO like this
public class OrderDetailDTO_2 //temp name
{
public decimal Quantity { get; set; }
public int ProductID { get; set; }
}
But I will end up with a lot of DTOs and even though I'm fine with it, what's the best practice for the DTO naming?
I don't see the point (from the posted info) in having an ID and a ProductId in an orderdetail because the ProductId should be sufficient; if the user adds 2 apples and then adds 3 apples, you can just set the order quantity to 5 apples for the single apples line, rather than distinctly track 2 apples vs 3 apples lines
I don't see the point in not having the price in the orderdetail; items always have a price. It might change or not, but there's no harm in communicating the price to the front end with every back and forth- the front end doesn't have to remember anything then, leading to my next point:
I also don't see the point in having the total in the order unless it is somehow ever going to be different to the sum of all the detail quantity * price. The client can do sums just like the server can. If the client knows the quantity and price, have it work out the total itself
I don't think OrderShip is well named. OrderShip is actually an Address, and looks like it could have plenty of uses in other parts of the program like a billing address, invoicing address, correspondence address. Name your objects according to what they are rather than what they are for - use the name of the variable to indicate what it is for:
public AddressDto ShippingAddress ...
public AddressDto BillingAddress ...
I was thinking of creating another DTO like this
Do not ever create a class name and just whack a 2 on it "because you couldn't think of a better name" - it is absolutely zero help in letting another developer (or yourself by the time you've forgotten this project) know the difference. Hands up anyone who can tell me every difference between an oracle sql VARCHAR and VARCHAR2 without hitting the manual (Gordon, this one's for everyone else ;) )
the method actually only requires property OrderDetailDTO.ProductID and OrderDetailDTO.Quantity for the business logic calculation.
You didn't post any code but there is a reasonable point in the comments that classes can inherit; the base class can have the common properties all classes have, the subclass can have more properties, plus it gets the base ones. The client could send a base class "I want to order apples, 3" and get a subclass "order item apples, 3, $1"
I'm not sure that these arguments warrant creating a whole new class just to dispense with 1 property though. I'd just reuse the same class and sometimes its price is filled in (server to client) and sometimes not/doesn't have to be/ignored (client to server, don't want client setting the prices!)
so I have a simple case, let's say I have a service with method called CreateOrder
Creating an order isn't what I'd call a simple case; it wouldn't need an SO question if it were - your create order method doesn't seem to ask for any payment related argument but the order dto tracks it, so I'm wondering if that is missed off? It's also something I would expect to be done at the end unless you're perhaps allowing the customer to build multiple baskets gradually, and the orderid is generated at the start as a basket reference (in which case perhaps there is a separate process for adding payment info)
At the end of all this, you perhaps need to sit down and map out your workflows first and what data they will need and aim to strike a balance between reusing one mega dto that tracks everything vs having a dto for every case and ending up with 1000 DTOs. These are the two extremes and you will almost never go there. There is always some element of reuse that can and should be applied to limit the maintenance headache. Feel free to inherit classes if they have sensible common base elements, but I wouldn't recommend you have a base OrderDto with the order Id and then DTOs for createorder, updateorder, cancelorder, addordershippingaddress, changeordershippingaddress, changeorderbillingaddress, reportorderreceived, reportordernotreceived etc - most of those operations only need an order Id, maybe an address detail or order detail; you can have a couple of dto; the base order (for operations like cancel, report received etc) and the full one (with null billing address if you're changing the shipping address).
You can use the name of the method being called to know whether it's the billing or shipping you need to change, or the client can just send a pair of modified addresses (both addresses need updating), a modified and unmodified address (update one address but not the other), a null and nonnull address (remove one address but not the other) ... and the server can process them all in the same way: the new address pair is the truth; overwrite the old data with the new.
This has struck a balance between the dto extremes; if we happen upon a situation where neither dto applies, then we can consider making another if no existing one is ideal. We shouldn't use fields for things other than which they were intended (don't use the credit card number field to store the phone number if they person pays by bank transfer) even if it is "just that one time" - perhaps adding a phone number would be an opportunity to extend the Address dto and call it something different like ContactDetail
At first you have to know your business logic and the required business entities. Without knowing any details about the application's business, the business logic can always be viewed as a black box, which requires input, processes this input and produces output i.e. a result (IPO model).
With the IPO model in mind, you can now design your business entities around the business logic. Identify the business process, derive the logic and design the required entities (their behavior or attributes and relationships). Start to design interfaces to describe those entities.
Note that it is not the goal to have a dedicated object for each method, so that each object only exposes the data the method needs. Although interface segregation is a good approach to achieve this, by encapsulating data contexts or responsibilities.
Since you have expressed your focused on naming conventions, also note that there is no value in adding a prefix or suffix to the type name that describes their physical (e.g. bool) or logical (e.g., DTO) data type. There is absolutely no value in this naming style. It only makes the names ugly and degrades readability. This is the main reason why e.g., Hungarian Notation is obsolete today.
Example
I assume that your business logic's goal is to create an actual order based on the data input provided by a user. This example of course is based on a very simplified process.
You can always use interface segregation to encapsulate responsibilities. An object that implements fine grained interfaces, can be passed around by this interfaces, allowing fine grained context related exposition of attributes.
Data input business entities
interface IItem
{
decimal Quantity { get; set; }
int ProductID { get; set; }
}
// Describes data needed for shipping related to a customer
interface IShippingAddress
{
string Address { get; set; }
string Province { get; set; }
string City { get; set; }
string District { get; set; }
string SubDistrict { get; set; }
string ZipCode { get; set; }
}
// Consolidates data needed to create an order.
// Provided by customer order process.
interface IPurchase
{
int CustomerId { get; set; }
IShippingAddress ShippingAddress { get; set; }
IEnumerable<IItem> Items { get; set; }
}
Data output business entities
// Result entity that extends IITem to add internal details like price.
interface IOrderItem : IItem
{
int Id { get; set; }
decimal Price { get; set; }
}
// Encapsulates contact details
interface ICustomerContactInfo
{
string Phone { get; set; }
string EmailAddress { get; set; }
}
// Encapsulates customer details like IsVip, or contact info etc
interface ICustomerInfo : ICustomerContactInfo
{
int CustomerId { get; set; }
string Name { get; set; }
}
// Consolidates the data needed for the shipping process
interface IShippingInfo : ICustomerInfo, IShippingAddress
{
}
// Consolidates and adds data needed for managing the order's delivery process
interface IDelivery : IShippingInfo
{
bool IsInDelivery { get; set; }
DateTime PickupDate { get; set; }
DateTime DueDate { get; set; }
}
// The result entity
interface IOrder
{
int Id { get; set; }
decimal PriceTotal { get; set; }
string Status { get; set; }
string PaymentMethod { get; set; }
IDelivery DeliveryInfo { get; set; }
ICollection<IOrderItem> Items { get; set; }
}
Business logic
public IOrder CreateOrder(IPurchase purchase)
{
// Get the result item info that contains actual price etc
ICollection<IOrderItem> orderItems = GetOrderItems(purchase.Items);
ICustomerInfo customer = GetCustomer(purchase.CustomerId);
IShippingInfo shippingInfo = CreateShippingInfo(purchase.ShippingAddress, customer);
IOrder result = CreateOrderItem(orderItems, shippingInfo);
return result;
}
public void SendConfimationMail(ICustomerContactInfo contactInfo)
{
SendMailTo(contactInfo.EmailAddress, message);
}
public void OrderDeliveryService(IShippingInfo shippingInfo)
{
SubmitDeliveryOrder(shippingInfo);
}
Example
public static Main()
{
IPurchase purchase = CollectOrderDataFromUser();
IOrder orderItem = CreateOrder(purchase);
// Only pass the ICustomerContactInfo part of IDelivery as argument
SendConfimationMail(orderItem.DeliveryInfo);
// Only pass the IShippingInfo part of IDelivery as argument
OrderDeliveryService(orderItem.DeliveryInfo);
}
The degree of segregation or the design of the interfaces may not make much sense for you. But the goal of this example is to provide a raw and basic example on how to design business entities, that reflect the business logic, which reflects the real life business process. It shows how interface segregation helps to pass around only a specific context (interface) of an object to enforce encapsulation or to limit greediness.
I'm preparing a project's data structure (code-first) in an ASP .NET Core 2 application, with the help of Entity Framework. This specific relationship I have no experience with: the user has to be able to choose diseases with checkboxes, and we have similar choices: cancer type, dietary, etc..
I have more than two tables like the ones on the picture, which will be referred from the UserKitProperties table. This table should work like a connector table, connects the user entity with other entities.
userid1 | cancertypeid1
userid2 | dietaryid1
userid1 | cancertypeid2
userid3 | dietaryid1
How should this be specified in the code, to support this relationship? I was thinking on doing a base class and maybe refer to that id. And this is the connector class..
public class PatientProperties : EntityModel
{
[Key]
public long ID { get; set; }
public long PatientID { get; set; }
[ForeignKey("PatientID")]
public Patient Patients { get; set; }
// this should be used for cancer type, dietary, etc..
public long PropertyID { get; set; }
/* Instead of using two classes' ids, maybe call the base class' id
[ForeignKey("PropertyID")]
public CancerType CancerTypes { get; set; }
[ForeignKey("PropertyID")]
public Dietary Dietaries { get; set; } */
}
Thank you in advance for your suggestions! :)
The following should work:
public class Property
{
public long PropertyId { get; set; }
}
public class CancerType : Property
{
// Your code
}
public class Dietary : Property
{
// Your code
}
public class PatientProperties : EntityModel
{
[Key]
public long ID { get; set; }
public long PatientID { get; set; }
[ForeignKey("PatientID")]
public Patient Patients { get; set; }
public long PropertyID { get; set; }
[ForeignKey("PropertyID")]
public Property Property { get; set; }
}
But as this MS doc mentions, setting up such inheritence will use a special Discriminator
column in the base class table, to represent what specific type is stored in a row.
I personally would resort to having nullable fields instead in order to not add more complexity. This doesn't enforce, however, that PatientProperties only has one property, which is a considerable minus:
public class PatientProperties : EntityModel
{
[Key]
public long ID { get; set; }
public long PatientID { get; set; }
[ForeignKey("PatientID")]
public Patient Patients { get; set; }
public long? CancerTypeID { get; set; }
[ForeignKey("CancerTypeID")]
public CancerType CancerType { get; set; }
public long? DietaryID { get; set; }
[ForeignKey("DietaryID")]
public Dietary Dietary { get; set; }
}
Instead of thinking about the database layout first, you should think about how you would represent this relationship in code. After all, you are doing a code-first approach.
There are basically two choices you could choose: Either the patient has multiple properties, one for each property type, or there is just a single collection for all properties:
public class Patient
{
// …
// option 1
public CancerType CancerType { get; set; }
public Dietary Dietary { get; set; }
public OtherProperty OtherProperty { get; set; }
// option 2
public IList<PatientProperty> Properties { get; set; }
}
Both of these options have their advantages and disadvantages. While option 1 is very explicit and enforces a single value for every type, it also requires you to have a (class) property for every (patient) property. So if you extend your model later, you will have to adjust your patient model.
Option 2 has the benefit that it can just collect everything. So you can just add properties to your patient without having to modify the model later if you introduce new properties. In addition, it would also directly support multiple selections for a single kind. On the downside, it does not verify anything on its own, so you need business logic to actually enforce your rules.
Moving onto the database, for option 2 you obviously need a link table since that is a many-to-many relationship now. Since you only have a link to the base type PatientProperty but you actually want to talk about the concrete type, you will need some kind of discriminator. Discriminators are basically just a notation to additionally store the kind of object in the database.
When storing data with inheritance, what is commonly done is “table-per-hierarchy”. That means that all types within the hierarchy of the PatientProperty base type will share the same table. A discriminator column is used to specify the type, and additional properties that some property types may have are implemented with nullable columns. This setup works out of the box with Entity Framework and is described in this chapter in the documentation.
The other approach, “table-per-type” is not supported in EF Core, so if you wanted to follow that, you would have to implement it yourself. But in your case, where the property types are mostly very similar, I would actually argue against that and actually keep them in the same table.
For option 1, as long as you only have a single property of each kind assigned to the patient, things are a bit simpler. Since you don’t have many-to-many there, you don’t actually need a link table. You just need to store the id for each linked property type in the patient model, as shown in the above UML. Doing that, you can also keep the property types as separate types that do not share a single table in the database.
I am working on an ASP.NET MVC4 application using EF 5 and Code First workflow. I have two entities:
public class Document
{
//other properties...
public int DocumentID { get; set; }
public virtual IList<UploadedFile> UploadedFiles { get; set; }
}
and:
public class UploadedFile
{
//other properties..
public int UploadedFileID { get; set; }
public int DocumentID { get; set; }
public virtual Document Document { get; set; }
}
In short - I have different kind of documents and each document may have 1 or more files associated with him. What I haven't thought about is that I'm going to have files that are not associated with a document. So I still need to save the file specific information and the UploadedFile entity has all the properties I need for that but I don't want to set values for the Document properties (leave them null). Which leads to the problem.
I already have some business logic written and if I change to public int? DocumentID { get; set; } - make the FK nullable I get compile errors from the code that I already have. Also, I might to decide and rewrite my code to reflect that change but I'm not sure if setting the FK to be nullable is best solution anyways.
The second solution that I can think of is to just create another entity OtherFiles (or something like this, just example name) where I will keep the records for the files that are not associated with some kind of document. Which will solve my problem in general but it seems like the worst solution since I'm gonna repeat all the properties of UploadedFile but without the relation to another table.
And third - if anyways I have to rewrite my code in order to keep some decent design (which I am trying to do) maybe there's a better way than setting the FK to null. I've watched a part of video tutorial by Scott Allen where he was setting two entities with the same structure, there it was Restaurant and RestaurantsReviews and in this video he didn't bother at all adding public virtual Restaurant Restaurant { get; set;} and had only public int RestaurantID { get; set; } saying that this is not mandatory but might be useful in some cases.
I don't know which cases are those, but maybe for my case it would be best just to remove DocumentID and virtual Document Document and rewrite my code? If this is the case what I lose as ability when I remove DocumentID from my UploadedFile entity?
Having the Id column and the virtual object to define the FK, helps when using lazy loading, and in many other ways. So if you have something like this:
public class Restaurant
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<RestaurantReviews> Reviews{ get; set; }
}
public class RestaurantReviews
{
public int Id{ get; set;}
public string Review { get; set; }
public int RestaurantId { get; set; }
public virtual Restaurant Restaurant { get; set; }
}
And for some reason you're working with the any Review and need the Restaurant's name, you just say:
var restaurantNameToShow = myReview.Restaurant.Name;
So EF is going to go again to the DB and get you the name (because he's lazy and didn't bring it in the first place). This answer your doubt about EF, regarding what option you should take, it's seems to me that is a very very complicated thing, and maybe a complicated solution ain't bad at all. For all the thing we spoke in the comments I'd choose the second option. If for some reason I get another idea on how solve it, I'm gonna tell it to you ;)
In my application I have Folders that can contain other Folders. They have all sorts of properties like this:
public class Folder
{
public Folder()
{
Sets = new Collection<Set>();
Folders = new Collection<Folder>();
Stage = Stage.one;
IsArchived = false;
DateCreated = DateTime.Now;
}
// Primitive Properties
[Required]
[Key]
public virtual int FolderId { get; set; }
public virtual int? ParentFolderId { get; set; }
[ForeignKey("ParentFolderId")]
public virtual Folder ParentFolder { get; set; }
[Required]
public int UserId { get; set; }
[Required]
public virtual string Title { get; set; }
public virtual string Details { get; set; }
[Required]
public virtual Stage Stage { get; set; }
[Required]
public virtual bool IsArchived { get; set; }
[Required]
public virtual DateTime DateCreated { get; set; }
[ForeignKey("FolderId")]
public virtual ICollection<Set> Sets { get; set; }
[ForeignKey("ParentFolderId")]
public virtual ICollection<Folder> Folders { get; set; }
}
Now, each User of the application has a "Home Folder" - a starting point. The Home Folder doesn't need half of the above properties however. I figure I have two options:
1) Use this entity and just add "isHomeFolder" as a property. This is simple but means I'll be sending blank [Required] properties over the wire for JSON requests - Home Folders don't have a title, can't be archived, etc.
2) Create another entity with just the required fields and duplicate the required properties there. This just doesn't seem very DRY, but feels better than the first option.
As a beginner programmer I'm not sure if there are any other options. Is there a standard approach/solution here?
In case it matters, I'm building on Entity Framework Code-First + WebAPI.
It depends on how many home folders you are going to have compared to total number of folders. If you are going to have a lot more second level folders than home folders (and you most probably will) then why bother implementing another structure just for the sake of 10 or 20% or requests.
As for required fields being empty – just use some default value that will not be parsed on the server side and you’re good ;).
2) Create another entity with just the required fields and duplicate
the required properties there. This just doesn't seem very DRY, but
feels better than the first option.
This is why ViewModel is important to avoid unnecessary (over) posting, posting values that you do not need. Also, to avoid the required fields in your entity where you would not want them or that they do not apply for "a specific view". An entity does not necessarily translate into a single view. Your case is one living example of it.
Is there a standard approach/solution here?
As I've mentioned, create a viewmodel and copy only the properties that you need to capture inputs for. This is not repeating yourself, even if you put dataannotations on the same properties. The data annotations on your viewmodel is for the view validation. The annotations on your entity is for domain validation. That is not repeating, IMO, as your UI is a different layer than your domain.
Maybe you should create a class which contains the common properties. Then you can use two classes that implement inheritance from the the first one.
Good morning everyone,
I am trying to tackle a problem I run into with EF code first. My schema is the following
public class Article : IUrlNode
{
[Key]
public Guid ArticleID { get; set; }
public string Title { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateUpdated { get; set; }
public string Summary { get; set; }
[System.ComponentModel.DataAnnotations.InverseProperty("CategoryArticles")]
public virtual IQueryable<Category> ArticleCategories { get; set; }
public string FriendlyUrl
{
get;
set;
}
}
[RouteChild("CategoryArticles")]
public class Category : ContentNode
{
public Guid ServiceId { get; set; }
[System.ComponentModel.DataAnnotations.InverseProperty("ArticleCategories")]
public virtual IQueryable<Article> CategoryArticles { get; set; }
}
I have written code with which I am able to retrieve a category from the database without actually knowing that its a category. From then on I must retrieve a single article of that category again without knowing that its an article. For categories I am relying on the ContentNode base class and for Articles on the IUrlNode interface.
Category retrieval works fine and with a single query but after I actually get the category I have to use reflection to get the navigation property pointed by the RouteChild attribute to find that single article that matches my criteria. Problem is that the navigation property type is ICollection which means that it will at best use lazy loading and will bring all the articles from the database and will find the one I am looking for in memory.
My problem is also described in this previous post (not by me):
Entity Framework Code First IQueryable
Is there a way to have that navigation property as IQueryable or some other design that can go around this limitation?
No there is no way to have navigation property as IQueryable but you can change the collection to IQueryable by using:
IQueryable<Article> query = context.Entry(category).Collection(c => c.articles).Query();
query.Where(...).Load();
Generally your "algorithm" looks pretty strange. You want to work with base class but in the same time you want to access child properties. That sounds wrong and it can most probably be solved in better way (non "generic" way is also better).