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.
Related
I'm trying a project using DDD. I'm confused on how to proceed. Here is a sample of my Entities. Tried to keep it brief.
But I'm struggling with the following
1. Update an address on a Person - there are business rules such as the Person must have X number of Address type.
I can grab the address from Person.Addresses and change it, but how would I validate Person is still valid when the changes were on the address?
2. If 2 addresses are required on creation. What would be the best way to to initialize the object? There could be more addresses on creation as well.
public class Person // AggregateRoot
{
public Guid Id { get; set; }
public Guid StatusId { get; set; } //FK to Status
private List<Address> _addresses = new List<Address>();
public IReadOnlyCollection<Address> Addresses => _addresses.AsReadOnlyList();
//more
public void AddAddress(...)
{
//Logic
_addresses.Add(...)
}
}
public class Status
{
public Guid Id { get; set; }
public string Name { get; set; }
//more..
}
public class Address()
{
public Guid Id { get; set; }
public string Address1 { get; set; }
public Guid AddressTypeId { get; set; }//FK to Address Type
}
public class AddressType()
{
public Guid Id { get; set; }
public string Name { get; set; }
}
The typical approach here is to control any operations on the child entities via the parent. In DDD parlance, the two entities working together is an aggregate and the Person entity is the aggregate root. All operations on the Addresses should be done via the Person - this gives the Person class the opportunity to enforce the invariants (rules) that apply even across the collection of Addresses.
As an example:
class Person
{
void UpdateAddress(Guid addressId, ...updatevalues)
{
var address = Addresses.Select(a => a.Id == addressId);
address.Update(updateValues);
VerifyAddressesCorrect();
}
}
The code outside the Person class should never call any methods on the Address directly.
To answer your second question, a common pattern would be to put the rules in a constructor overload, or if that doesn't suit, a static factory method on the Person class. This gives you a lot of flexibility for how you structure the input and what rules you enforce at the time the entity comes into existance.
Personally I like the static factory method because it allows you to give a more meaningful name to what is going on when the class is instantiated. I try and avoid terms like Create because there's usually a more domain oriented term, like Person.Register() or Person.Onboard()
Similarly, the .UpdateAddress method is not great as Update is a crud term that doesn't shed much light on the domain - what is actually happening here from the user's/domain perspective? Sure, sometimes an update is just an update (e.g. a data entry error needs correcting), but it can be a prompt to consider if there is a more meaningful domain concept at play.
I have studied many articles about how to config one to one relationships. I have learned it.
But I couldn't understand how to find a dependent entity in one to one relationship?
For instance, we have two entities User and Developer. How to understand which of them is a dependent entity? Because I think we must add a foreign key to a dependent entity. So the first things to do, we need to find a dependent entity.
public class User
{
public int Id {get;set;}
public string PasswordHash { get; set; }
public string FullName { get { return FirstName + " " +LastName;}}
public GenderType Gender { get; set; }
public bool IsActive { get; set; }
public DateTimeOffset LastLoginDate { get; set; }
public string FirstName { get ; set ; }
public string LastName { get; set; }
}
public class Developer
{
public int Id { get; set; }
public byte Image { get; set; }
public int Age { get; set; }
public string Resume { get; set; }
}
A dependent is something that depends on something else. A baby is dependent on its mother for food etc. Identify which entity can stand alone, without the other.
For example, you may decide that a User might not be a Developer but a Developer is always a User - in this case your relationship is actually 1:0..1 (user:developer) and you're looking at Developer being a subclass of a User. If. You could alternatively arrange things in a has-a fashion, and Developer has a User property (but User doesn't have a Developer property because not every User is a developer)
You may decide that you can never have one without the other- in which case they would probably be a good candidate for being in the same table/same client side entity
To some extent the question can be academic; there may be situations where you want to treat one as dependent, and others where it's the inverse way round. It'll probably help you overall though if you make a decision about how your entities are related on the client side and this will drive how you map them on the database side
This is for the first time I am implementing the concept of Domain Driven Design in a real project. The project is about generating a permit for employees which would enable them to enter company premises. Through an Intranet site, an employee who already possesses an Employee ID, will be able to apply for a permit or apply for replacement of a permit, in case the permit is damaged or lost. And an administrator will process the applications and hand over a physical permit in the end.
I have a couple of entities - User, Permit and one Value Object - Employee.
A User can be entirely identified by an Employee. Should I create a UserId as well? How do I handle the case in which the administrator may not only approve, but raise an application on behalf of an employee as well?
The Value Object Employee has an Id property EmployeeId which I know goes against the principle of a Value Object. However, in my case, Employee is read-only. It doesn't matter to me if I get only the EmployeeId or the Employee as a whole. Am I doing this right?
The Permit entity contains a lot of properties. How do I break down the properties of Permit into Value Objects?
public class User : Entity
{
public Employee Employee { get; set; }
public bool IsAdmin { get; set; }
}
public class Permit: Entity
{
public int ApplicationId { get; set; }
public string EmployeeId { get; set; }
public string Type { get; set; }
public string Status { get; set; }
public DateTime RequestDate { get; set; }
public DateTime IssuanceDate { get; set; }
public string IssuanceReason { get; set; }
public string SurrenderReason { get; set; }
}
public sealed class Employee : ValueObject<Employee>
{
public string EmployeeId { get; private set; }
public string Name { get; private set; }
public string Department { get; private set; }
public string Division { get; private set; }
public string BirthDate { get; private set; }
public string Designation { get; private set; }
public string BloodGroup { get; private set; }
public string SecurityLevel { get; private set; }
public string EmploymentDate { get; private set; }
}
Apart from the concerns, I'd be grateful if someone could guide me to go about it in the most appropriate manner possible. Thanks.
In modeling business processes, it will often help to think about the paperwork, rather than the things in the real world. The process begins when somebody files a request document, it ends when the adminstrator files an approval or a rejection, and so on. The domain model's job is to do the bookkeeping, and to perform some of the logic on behalf of the business.
See
Rinat Abdullin: Evolving a Process Manager...
Greg Young: Stop Over Engineering
Should I create a UserId as well?
If you need to handle the case where the person submitting the request is different from the person the permit is assigned to, then you should absolutely treat those as different values.
It doesn't matter to me if I get only the EmployeeId or the Employee as a whole. Am I doing this right?
Yes - there is nothing wrong with an immutable value having an identifier.
In more sophisticated models, value objects will often be composed from other value objects. For example, event though EmployeeId and BloodGroup are opaque character sequences, it's probably not OK to pass a blood group to a method that is expecting an employee id, or vice versa. So rather than leaving things "stringly typed", we might invest more work in the model to make those concepts explicit.
How do I break down the properties of Permit into Value Objects?
Again, values can be composed from other values. If there is a subset of cohesive properties, group them together.
Scott Wlaschin's Domain Modeling Made Functional is a great reference here.
Part of the point of "objects" is that we should be able to change the in memory data structures and still have everything "work". So you shouldn't feel like you are committed to a particular in memory layout.
(Note: it's really easily to couple your in memory layout to your persistent storage -- that will make things harder to change later; so try not to fall into that trap more than once.)
From my point of perspective it would be better to discard the User class, as it closely resembles the Employee class.
The property IsAdmin is a very hard constraint, from a broader perspective you could create an Enum that represents security groups. This enables you to implement security for certain areas where given group X has access and group Y does not. This could replace the string SecurityLevel in the Employee class. You could also implement these security groups in the Permit class.
The Permit class should be used by the Employee class. A user can have multiple permits, active and non-active. A boolean value defining that logic should be implemented into the Permit class. By implementing the active/non-active boolean in the Permit class, you could revoke access by simply switching the value of the boolean.
I'm having 3 models Items, Branches and ItemsInBranches defined as follows
public class Items
{
public int Id { get; set; }
public string Barcode { get; set; }
public string Name { get; set; }
public int SizeId { get; set; }
public int Price { get; set; }
public int DiscountId { get; set; }
public int ShortageMargin { get; set; }
[NotMapped]
public double ActualPrice
{
get
{
double amount = ((double)Price * (double)Discount.Amount / 100);
double price = (Price - amount < 0) ? 0 : Price - amount;
return price;
}
}
public Discounts Discount { get; set; }
public ItemSizes Size { get; set; }
public ICollection<ItemsInBranches> ItemsInBrach { get; set; }
}
public class Branches
{
public int Id { get; set; }
public string Name { get; set; }
public string Location { get; set; }
public ICollection<Employees> Employees { get; set; }
public ICollection<TransactionLog> TransacionLogs { get; set; }
public ICollection<ItemsInBranches> ItemsInBranch { get; set; }
}
public class ItemsInBranches
{
public int Id { get; set; }
public int ItemId { get; set; }
public int BranchId { get; set; }
public int Amount { get; set; }
[NotMapped]
public bool IsShort
{
get
{
return Amount < Item.ShortageMargin;
}
}
public Items Item { get; set; }
public Branches Branch { get; set; }
}
whenever I try to load items in branches using the following code I Branch navigation property gets loaded just fine but I the Items is always set to null
public IEnumerable<StorageViewModel> GetStorage(int? BranchId)
{
var storage = Find(x => true).Select(s => new StorageViewModel
{
Amount = s.Amount,
BranchName = s.Branch.Name,
ItemName = s.Item.Name,
SortageMargin = s.Item.ShortageMargin,
IsShort = s.IsShort
});
return storage;
}
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return _dataContext.Set<TEntity>().Where(predicate);
}
I made sure the ItemId and BranchId are set to foreign keys for the Items and Branches tables in the database, they don't allow nulls and they enforce foreign key constraints
could anyone tell me why only the Branch get loaded while Item is always set to null
Generally you shouldn't try to wrap frameworks, particularly EF with helper methods like you're doing with your Find method, which I mention because that is why you're running into this problem (rather it's making the solution harder than it would otherwise have to be without the helper).
You may run into this problem you ran into (or where you want to specify AsNoTracking() in your Find one day when you find out about the ChangeTracker and how it works and SaveChanges() starts running slow or you have a large memory footprint due to having too much attached at once. Of course this is problem more with EF because it makes it too easy for people to develop without really understanding important concepts like transactions - the details of the layer it's trying to abstract away...)
You would need to load related entities somehow. I'd recommend reading this link and choosing an option. Here's one option on that link that only touches your GetStorage method, which might "solve the problem easily" but may not be good performance-wise if there are a lot of records - considering your predicate is including everything, though, there may not be a lot. I can't give you a better recommendation without seeing more of your code. If it's loading one and not the other and they're otherwise identical (same non-nullable FK and there's a corresponding record) then I think it's probably configuration somewhere... again read the link to see how to configure loading of navigation properties. Note this will probably generate multiple SELECT statements; I couldn't think of a better way (besides dropping down into Set<>) with the constraints of using Find inside GetStorage to grab the missing records you needed. If you could call the Find from a different class that has a different TEntity specified then you could probably get just the Items records you need in one SELECT statement - but I don't know how you're setting up your services and their lifecycles. That might be a compromise between performance and not having a mass-refactoring of the data access wrappers.
var allEntities = Find(x => true).ToList();
allEntities.ForEach(x => _dataContext.Entry(x).Reference(y => y. Item).Load());
var storage = allEntities.Select(s => new StorageViewModel
// ...
GetStorage seems like it's specific to one TEntity; Your Find method seems like it has TEntity defined as a generic in the containing class - so if I had to guess those methods are in (2) different classes even though you put them back-to-back. Your Find method is then probably on a class that abstracts away EF to give you a "simpler" interface to the database. EF is already that simple interface to the database; you don't need another.
What you could be doing instead is making concrete repositories that take a hard dependency on specific TEntity's and depend on a DbContext and then having either your domain logic taking a dependency on your repositories (which would require you to mock the repository somehow - either with a pseudo database, actual database or a leaky in-memory database to "unit" test your domain logic) or having your repositories totally de-coupled from your domain logic, enabling fast-executing domain logic unit tests. Then your repositories have shielded the rest of the application from EF, so you could change it out to ADO.NET or a lighter weight ORM like Dapper.
A Find method like that is an EF abstraction - you've tied whatever depends on that to EF (and your schema, probably) even if you didn't realize it. What I briefly described is true a database abstraction - which actually would free you up to change your data access (and schema) if you needed to - just change out the repository implementation without changing its API or behavior...
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..