C# Entity Framework Table Per Type adding unwanted column in base table - entity-framework-4

In C# I'm using Entity Framework and MVC and have:
public class Part
public class FinishedGoodsPart: Part
public int? ProductLineId { get; set; }
public class CompetitorPart : Part
public int? ProductLineId { get; set; }
public class OEPart: Part
public class ProductLine
public virtual ICollection<Part> Parts { get; set; }
Observe that FinishedGoodsPart and CompetitorPart have a ProductLine, but OEPart does not.
This puts a column called ProductLine_Id in the FinishedGoodsPart and CompetitorPart tables, as I expect and want, but also puts column ProductLine_Id in table Part (which I do not want).
How do I prevent E.F. from adding column Part.ProductLine_Id? Is there a better design?
The goal is that an instance of the ProductLine model object will have a list of all parts which belong to that product line (whether they are competitor or finished goods parts). But an OEPart is not allowed to have a ProductLine set.
FinishedGoodsPart objects will have a lot of attributes, whereas CompetitorPart will have very few, therefore I don't want to store all part records in a single database table.

Related

Many to Many in EF core

I have the following models
public class Student
{
public int Id {get; set; }
public string Name {get; set; }
public ICollection<StudentToCourse> StudentToCourse {get; set; }
}
public class StudentToCourse
{
public int StudentId{get; set; }
public Student Student {get; set; }
public int CourseId{get; set; }
public Course Course {get; set; }
}
public class Course
{
public int Id {get; set; }
public string Name {get; set; }
public ICollection<StudentToCourse> StudentToCourse {get; set; }
}
I want to get a list of all COURSE per student ID, how do I go about doing that?
Short answer: SELECT and match on the Id values. Or programatically -
foreach(Student s in yourstudentList)
{
foreach(StudentToCourse stc in s.StudentToCourse)
{
if(stc.StudentId = s.Id)
//this is one you want, do something with it
}
}
Better answer:
First let's look at your model...
Imagine the underlying database structure.
Your middle table is known as a lookup.
You don't really need the entire Student, nor the entire Course object in it.
Also, your Course object does not need to know about either of the other objects.
If you can imagine three tables in your database you can see how you would logically connect a Student to a Course across the three tables.
Your model is still incomplete though. Within your application you still need a container, in this case a List courseIds. In this way your Student doesn't need to care about all the entries in the Student/Course lookup table, just the ones applicable to the particular Student. And you have an easily accessible object to pull data from, or send updates to, the database.
On initial population of the courseIds collection you would do a
SELECT FROM StudentToCourse where StudentId = x
You can then JOIN on your Course table to pull values such as the Course name.
If you find you need to do a lot of those look ups you may cache your Course list and lower your database traffic at the cost of some ram.
Each time you make a new student you would want to populate their list of course Ids and when committing the student to the database you would save your look up table.
This keeps your objects as lightweight as possible while maintaining their relationships.
There are various ways to write the SELECT statement in your dev environment, search them out and find one you like (or that matches your company's current practices) and get used to consistently using the same one. It will keep your code more readable and manageable.

ASP.NET MVC Entity Framework: Data Annotations

I'm working with Entity Framework with a database-first approach. I already defined the model inside my application. Now I'm working with controllers and views. I used scaffolding in order to create controllers. Now I want to create rows.
Let's say I want to create employees, and let's say the DBA and EF made this possible:
public partial class TBL_EMPLOYEE
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public TBL_EMPLOYEE()
{
this.TBL_EMPLOYEE = new HashSet<TBL_EMPLOYEE>();
}
public int EMPLOYEE_ID { get; set; }
public String CO_WORKER_NUMBER { get; set; }
public string NAME { get; set; }
public string LAST_NAME { get; set; }
public string SALARY { get; set; }
public string PHONE_NUMBER { get; set; }
public string EMAIL { get; set; }
public string { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
}
Now, I need a view to create an employee, let's call this view VIEW 1
In this view, the user only needs to specify name and last name values. Both are required.
Now, in this VIEW 1 case I could use the following data annotations attributes in the same class, that'd be:
[Required]
public string NAME { get; set; }
[Required]
public string LAST_NAME { get; set; }
Now, let's go to the next case. I need another View, let's call this VIEW 2
In this one, the user needs to specify all values for all attributes. All of them are required except for name and last name.
THE REAL QUESTION
How can I use the same model class for both views? The example above here might seem a bit silly and trivial validations but I've been in bigger projects where entities are bigger and the idea of having different ViewModel classes is just so much work.
I've stumbled upon this in my .NET developments, to the point I had to create a ViewModel class per view in order to be specific with what the user needs to input and their validation. Is this the only way?
To avoid duplicating models with minor variations, try this:
https://stackoverflow.com/a/18898112/6850962
Basically, create a base model with data annotations that apply in all situations (eg: DisplayName) and then extend the model for variations (eg: Required attribute).
If you are trying to use your Entity Framework entities approach, I wouldn't put validation attributes on those entities. I would either:
create separate distinct classes and then copy data from the EF entities to the models, and vice versa on update (either by writing the code explicitly, or using a tool like AutoMapper or many others). Then you can define the validation rules anyway you want. Unfortunately this approach does tightly couple validation to the model and thus model reuse may not be as possible.
Use a more fluid validation framework like FluentValidation (https://github.com/JeremySkinner/FluentValidation). The benefit to this is that you define an external class with the rules internal, which can be applied differently depending on the situation. The model may still need some indicator on the model itself to figure out which rules apply, but this is another functional approach to handling the scenario you describe.

DAL, BLL and Web layer - create the same class for each layer? Is it correct?

For example: I need to display comments from Comments table in database.
So in DAL project I have POCO class:
public class Comments
{
public int CommentId { get; set; }
public string Author { get; set; }
public string Content { get; set; }
}
In BLL project I have class (DTO - data transfer object):
public class CommentsDTO
{
public int CommentId { get; set; }
public string Author { get; set; }
public string Content { get; set; }
}
So I get IEnumerable from DAL, convert to IEnumerable and return it to Web project.
In Web project I have class:
public class CommentsViewModel
{
public int CommentId { get; set; }
public string Author { get; set; }
public string Content { get; set; }
}
So in Web project I get IEnumerable from BLL, convert to IEnumerable and return it to view.
Is it correct? Because these classes have only different names.
It is certainly incorrect and you should not do this generally ad this just duplicates the code. You need different classes only when they differ. Suppose that you want to display a Comment in your web application and Comment is associated with User entity. Then, instead of sending 2 object separately you just create DTO class that combines properties of the two (like comment text and user name). Then sometimes you need to change the model in your web application to display data properly. For instance you want to display them in grid, and to do that properly you need to assign some attributes over properties and this is a good reason to create separate model in your web application. If you do not need to change your classes you should reuse existing ones. However even in your case changing CommentsViewModel a bit might be beneficial - usually you do not want user to see CommentId value (this is db internal thing) - so you can this field in [HiddenInput(DisplayValue = false)] so you could use Html.EditorForModel just to display editor panel. But this is your choice.
Creating each class for every layer is certainly beneficial for large projects. When I say large, I mean exceeding 5 developers with a application lifetime of 10 years. On large projects, the disadvantage of duplication becomes small compare to the benefit it provides.
For small projects, it is certainly overkill. The extra weight will slow you down with little or no benefit. Its like packing 7-day clothes on a 2 day hiking trip.
The larger the project, the more formal is your architecture.
With that said, here is my advice:
The Comment should be shared by the DAL and Business Layer.
If you don't have a "service layer", loose the DTO classes and map the Comment straight to the CommentViewModel. More about the service layer
I say Comment without "s" because only classes that represents collections should be named plural.

With MVC/Entity Framework, how does one manage housekeeping tasks in the view?

My understanding is that only one model can be passed to the view at a time. The problem with this that I see is that I am being forced to pass the Entity Framework model, and not any model that will manage housekeeping in the view. Here is what I mean:
You need to make a page that allows someone to submit Cars to the database. Along with the form fields (e.g. CarName, CarMake, CarYear) you also need a checkbox at the bottom of the page called "Remember Values" which when checked will "remember" the form values when the user clicks the Submit button at the bottom, so when they return all of their form data is still in the form fields. Needless to say, this Remember Values variable is not part of the Entity Framework model- it is just a housekeeping variable for use in the view.
How would you guys handle adding this checkbox? It feels like it should be part of the model, but I can't send two models to the view. Am I just looking at this issue wrong? What would you recommend?
.NET 4.5/MVC 5/EntityFramework 6
This is a good situation to be using ViewModels.
Build your ViewModels with all properties that you'd want to send/retrieve to/from your view. For example:
EF Entity
public class Car {
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual string Make { get; set; }
public virtual string Year { get; set; }
}
View Model
public class AddCarViewModel {
public Car Car { get; set; }
public bool RememberValues { get; set; }
}
Controller
public class CarController : Controller {
// Constructor....
public ActionResult Add() {
var vm = new AddCarViewModel();
return View(vm);
}
[HttpPost]
public ActionResult Add(AddCarViewModel vm) {
if (ModelState.IsValid) {
_carService.Save(vm.Car);
}
return View(vm);
}
}
Another good approach is to create Domain Transfer Objects, which are POCO classes to hold data that is transferred through the pipes. For example, in your business layer you may want to audit any changes to your Car model. So you may have properties like CreatedBy, CreatedDate, UpdatedBy, UpdatedDate, etc. (These properties are generally never displayed to the end-user but are important to store).
So you'd create the following classes:
public class Car {
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual string Make { get; set; }
public virtual string Year { get; set; }
public virtual User CreatedBy { get; set; }
public virtual User UpdatedBy { get; set; }
public virtual DateTime CreatedDate { get; set; }
public virtual DateTime UpdatedDate { get; set; }
}
public class CarDTO {
public Guid Id { get; set; }
public string Name { get; set; }
public string Make { get; set; }
public string Year { get; set; }
}
and you can use a library such as AutoMapper to map properties from Car -> CarDTO:
var car = _carService.GetCarById(id);
var carDTO = Mapper.Map<Car, CarDTO>(car);
This way, you can choose which properties you want exposed to your views by utilizing DTO's.
I always create an additional model that I can convert to and from between the EF model.
This additional model gets passed to the View and holds al the neccesary properties like CarName, Carmake, CarYear, Remember and probably most importantly, the Id of that particular object.
So when the user submits, this model gets passed to the Post method where you can extract all the required properties. You fetch the database model using the Id from your DbContext and update the properties with the values that were just passed through.
Technically you can send two models to the view, if the model is actually something like a Tuple:
#model Tuple<SomeEFModel, SomeViewModel>
Though that's kind of ugly. And if you're creating a view model anyway you might as well just make it a composite of the Entity Framework model. Something like:
public class SomeViewModel
{
public SomeEFModel EFModel { get; set; }
public string SomeOtherProperty { get; set; }
// other stuff...
}
Then just build an instance of that in the controller and send it to the model:
#model SomeViewModel
You could even just de-couple the EF model and the view model entirely, creating a custom view model that has everything for that view and then translating to/from that and the EF model at the controller level. Ultimately it comes down to what implementation looks cleaner and is easier to maintain, which can differ from one context to another.
Edit: Another option, if the models get unwieldy for whatever bits of the framework you're relying on, could be to separate your outgoing and incoming models. For pushing data to the view, you can use the composite view model above. But then when the data comes back from the view just use a normal Entity Framework model and a couple of additional parameters for your additional fields:
public ActionResult Edit(int id)
{
// build the view model with the EF model as a property
return View(someViewModel);
}
[HttpPost]
public ActionResult Edit(SomeEFModel model, string someOtherProperty)
{
// here you have an EF model from the view like normal
// plus the additional property (however many you need)
// you can even create a separate view model to collect the other properties
// as long as the names are well defined, the model binder should build both
}
First, you absolutely should NOT be passing your EF models directly to your view, and you should certainly NOT be posting directly to your EF models. This is essentially taking untrusted, unsanitized input and directly writing it to your data model with only bare minimal validation.
While this may work with simple models with no security or other ramifications, imagine a situation where you allowed a user to edit his profile information. Further, imagine that in his profile you also stored information relating to his subscription information. A specially crafted submit could alter his subscription information and give himself free access to your site, or worse...
Instead, you use view models. Apart from the security aspects, view models are good because other than in very simple CRUD style sites, your views requirements are typically different from your data models requirements. For instance, a particular field might be nullable in your data model, but you might want to make it required in your view. If you pass your model directly, then you can't do that easily.
Finally, Aggregate view models aggregate many different submodels to provide an overall model for the view, which is what you are getting at. You would then use a service layer, repository, or business logic layer to translate your view model to your data model, massaging data or applying logic as needed.

If you are using Entity Framework, how to do you use the EF Model classes instead of having to make custom View Models?

I am new to MVC. If one imports all of their existing tables in a database, they can created Entity Framework models. My question is, how do I actually use these models instead of having to fall back on creating custom View Models of the table data? Here is what I mean:
My understanding is that model classes that Entity Framework automatically generates should not be modified (example: a model of a Products table). Because of this, I have to create a whole new View Model of the Products table in order to be able to add things like [Display] and [Required] tags to the model so that I can have a custom name displayed to the user (e.g. "Store Products") and validation (e.g. the product name field is required).
See what I mean? Do you always have to manually create a View Model in order to get needed functionality like validation and user-understandable display names?
Side question: the models that Entity Framework automatically creates (based on your existing tables in the database) are called "Domain Models" right?
If the only reason you want to make separate view model is because you want to add data annotations then you can just use partial classes
eg: Given an EF generated class
public partial class MyClass
{
public int Id { get; set; }
public string SomeText { get; set; }
}
you can add a new file with:
[MetadataType(typeof(MyClassMetadata))]
public partial class MyClass
{
}
public class MyClassMetadata
{
[Required]
[Display(Name = "An Id")]
public int Id { get; set; }
[AllowHtml]
[Display(Name = "Some HTML text")]
public string SomeText { get; set; }
}
to decorate your EF classes.
Yes, this looks a bit clunky. There might be a neater way to do this in the newer versions.

Resources