I have created an MVC 4 application with EF db-first using ADO.NET Entity Data Model.
I've previously been adding data validation and updating constructors directly into the generated Model classes, but as I foresee these tables to be updated I don't want to have to add these all back in, plus I shouldn't be editing these auto generated classes anyway.
Using Metadata.cs and PartialClasses.cs from http://www.asp.net/mvc/tutorials/mvc-5/database-first-development/enhancing-data-validation I'm not sure the best way to update the default constructors for these Model classes.
Here's an example model, simplified.
Within .edmx
public partial class Campaign
{
public Campaign()
{
this.Fees = new HashSet<Fee>();
}
public int ID { get; set; }
public string Name { get; set; }
public string CreatedBy { get; set; }
public System.DateTime CreatedOnDate { get; set; }
public virtual ICollection<Fee> Fees { get; set; }
}
within ParticalClasses.cs [errors as the generated Modal class defines the default constructor]
[MetadataType(typeof(CampaignMetadata))]
public partial class Campaign
{
public Campaign()
{
this.Fees = new HashSet<Fee>();
// Non-Generated
this.CreatedOnDate = DateTime.Now;
}
}
I have other models I would also like to have other constructors with different parameters, so to simplify my question, where do I add constructors for DB first MVC as to no update the generated Model classes?
Not 100% sure about what you are trying to do, but I'll try to answer your question.
First of all, it seems that you are missing the point of the MVC: your link refers to view model validators, but you are talking about data models. Two VERY different things. There's nothing to validate in a data model - those change and are govern by what's going on in the database.
This is what I would do:
1) Create a data layer: this would hold all your entity classes.
2) Create a service layer: this will instantiate and populate the entity classes using either raw sql, or a pattern (repository pattern, for exam).
3) Create your website: this will hold your controllers, view models (they are the ones you want to validate) and views.
For your Campaign class:
public interface IEntity
{
object EntityID { get; set; }
}
public abstract class BaseEntity: IEntity
{
public abstract object EntityID { get; set; }
}
public class Campaign : BaseEntity
{
#region Properties
public int ID { get; set; }
public string Name { get; set; }
public string CreatedBy { get; set; }
public DateTime CreatedOnDate { get; set; }
public virtual List<Fee> Fees { get; set; }
#endregion
#region BaseEntity Implementation
public override object EntityID
{
get { return this.ID; }
}
#endregion
#region Constructors
public Campaign()
{
this.CreatedOnDate = DateTime.Now;
this.Fees = new List<Fee>();
}
#endregion
}
//View model
//THIS is the class you want to validate
public class CampaignViewModel
{
#region Properties
public int ID { get; set; }
[StringLength(50)]
public string Name { get; set; }
[Required]
public string CreatedBy { get; set; }
public DateTime CreatedOnDate { get; set; }
public Fee AssociatedFee { get; set; }
#endregion
#region Constructors
public CampaignViewModel()
{ }
public CampaignViewModel(Campaign data)
{
this.ID = data.ID
this.Name = data.Name;
this.CreatedBy = data.CreatedBy;
this.CreatedOn = data.CreatedOn;
this.AssociatedFee = data.Fees.Where(x=>x.Active && x.ID == this.ID);
//Just an example
}
#endregion
}
Also, you could use Fluent Validation for a more in-depth separation of concerns. (http://fluentvalidation.codeplex.com/)
Related
I am developing an application in asp.net mvc. I use entity framework as ORM. I have a problem. To use javascript unobstrusive validation, I need to add annotation to model objects. For example; [Required], [EMailAddress]. But when we add something to the database and update it, all model classes are override, and all annotations disappear. Or, as soon as you open edmx, automatic model classes are automatically override. How can I solve this problem. There are dozens of screens and classes, the slightest change in edmx erases the annotation in all classes, causing huge waste of time.
// <auto-generated>
using System.ComponentModel.DataAnnotations;
namespace MerinosSurvey.Models
{
using System;
using System.Collections.Generic;
public partial class Surveys
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Surveys()
{
this.SurveyQuestions = new HashSet<SurveyQuestions>();
this.SurveyCustomers = new HashSet<SurveyCustomers>();
}
public int SurveyId { get; set; }
[Required(ErrorMessage = "Plase enter survey name.")]
public string SurveyName { get; set; }
[Required(ErrorMessage = "Please enter survey description.")]
public string SurveyDescription { get; set; }
// [DataType(DataType.Date)]
public System.DateTime? CreatedDate { get; set; }
//[DataType(DataType.Date)]
public System.DateTime? UpdatedDate { get; set; }
public int CreatedUserId { get; set; }
public bool IsActive { get; set; }
public bool Status { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<SurveyQuestions> SurveyQuestions { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<SurveyCustomers> SurveyCustomers { get; set; }
public string Token { get; set; }
}
}
Editted for
Metadata
Surveys Partial & Metadata
//PartialClass
[MetadataType(typeof(SurveyMetadata))]
public partial class Surveys
{
}
//Metadata
public partial class SurveyMetadata
{
public int SurveyId { get; set; }
[Required(ErrorMessage = "Lütfen anket adını giriniz.")]
public string SurveyName { get; set; }
[Required(ErrorMessage = "Lütfen anket açıklamasını giriniz.")]
public string SurveyDescription { get; set; }
// [DataType(DataType.Date)]
public System.DateTime? CreatedDate { get; set; }
//[DataType(DataType.Date)]
public System.DateTime? UpdatedDate { get; set; }
public int CreatedUserId { get; set; }
public bool IsActive { get; set; }
public bool Status { get; set; }
public virtual ICollection<SurveyQuestionMetadata> SurveyQuestionMetadatas { get; set; }
public virtual ICollection<SurveyCustomerMetadata> SurveyCustomerMetadatas { get; set; }
public string Token { get; set; }
}
GetData Ajax Event
// GET: Survey
public ActionResult GetData()
{
using (MerinosSurveyEntities entity = new MerinosSurveyEntities())
{
List<Surveys> surveys = entity.Surveys.Where(x => x.IsActive && x.Status)
.OrderBy(x => x.SurveyId).ToList();
return Json(new { data = surveys }, JsonRequestBehavior.AllowGet);
}
}
How I should change my GetData event.And what list should go to the client side??
Best Practice is, use ViewModel[Not Entity/Model classes] to manipulate / play at Client Side.
So use ViewModel, Inherit Model classes and then use Annotations
For eg.
Public class ViewModelClass: ModelClass
{
[Required("First Name is Required")]
Public String FirstName {get; set;}
}
For do such thing you can use partial classes and use "ModelMetadataType" in .net core annotation above your class.
lets do it in code:
this is your model that is created in edmx:
public partial class Student{
public string FirstName {get; set;}
}
first of all you have to create a partial class in another file with same name as student class and be careful its name space should be same as above class. (classes must be out of edmx file)
[ModelMetadataType(typeof(StudentMetaData))]
public partial class Student{
}
and at the end you must create your metadata class like this:
public class StudentMetaData{
[Display(name="First Name")]
public string FirstName {get; set;}
}
now you can update your edmx file without changing the data annotations in your metadata classes.
https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.metadatatypeattribute?view=netframework-4.8
Working from memory at the moment, but the EF classes are always partial so create another partial implementation of the same class, then add the Interface and Metadatatype binding to that.
// Entity Framework Model
public partial class User
{
public string Email { get; set; }
public string Password { get; set; }
}
// Your Interface with data annotations
public interface IUser
{
[Required]
string Email { get; set; }
[Required]
string Password { get; set; }
}
// Partial Model appling the interface to the entity model
[MetadataType(typeof(IUser))]
public partial class User : IUser
{
}
Under this approach, in the future, you only need to worry about updating your interface should you add new properties
Copy the generated CS files (the one's with your table names) that you've already added your annotations to, to another folder, then overwrite the newly generated ones, I do it this way and shall continue to until there's a more hassle-free way to do it.
I need to audit data in some tables in my server database so my clients can take partial updates (by table/entity). Data in the server database is only edited from the server website.
The audits will be requested by a client: WHERE Id > [Clients Last Id], the server will then do some processing and then return the latest audits to keep themselves up to date.
I can't seem to get to a generic pattern that will work across the board for all of my models:
public class Domain {
public int Id { get; set; }
public string Property1 { get; set; }
public int Property2 { get; set; }
}
Then I think I want to be able to do something like so:
public class DomainContext : DbContext {
public DbSet<Domain> Domain { get; set; }
public DbSet<History<Domain>> DomainHistory { get; set; }
}
This is my problem class taking this route, I want to inherit from Domain so things like property changes and EF migrations (in code first) will 'just work'. But I Cannot derive from 'T' because it is a type parameter
public class History<T>
: T //Cannot derive from 'T' because it is a type parameter
where T : class {
public DateTime CreatedOn { get; set; }
public int CreatedByUserId { get; set; }
public int EntityFK { get; set; }
// This will always be the current version
//public T Entity { get; set; }
// I could store a snapshot of the state at the time of the audit
public string XMLData { get; set; }
}
I don't know if my use of generics is warranted here but I'm basically trying to get to a point where I can do the below so my models play nicely with EF Migrations:
Domain d = GetDomainModel();
History<Domain> dh = new History<Domain>();
dh.Property1 = d.Property1;
dh.Property2 = d.Property2;
How can this be done?
For a basic audit of your entities you can use a base class and intercept the changue type in a override of savechangues in context, like this (sorry of format, i write in mobile):
public class AuditBase
{
//Adapt your requirements, the propertys are exists in db
public datetime creationdate { get; set; }
public datetime modificationdate { get; set; }
public string creationuser { get; set; }
public string modificationuser { get; set; }
}
public class ModelBBDD : AuditBase
{ }
You can override the SaveChanges method of Context. In the method, you can through the ChangueTracker property of Database Class for added or updates dto's, like this:
var dto = entity as auditbase;
if (dto == null) continue;
if (dto.state == entitystate.added)
{
((Auditbase)entity).creationdate = datetime.now;
((Auditbase)entity).creationuser = environment.username;
}
else if( dto.state == entitystate.modified)
...
...
If you can log all the changues of properties, you can trough all the properties of dto with reflection and type in SaveChanges, and save values in log.
I created an inheritance hierarchy after a few migrations. Now when I update the database using code first migrations, code-first is not automatically creating the discriminator field. I have since dropped the table and recreated it (using code-first migrations) without any luck. The only thing I can think of is that there are no additional "non-virtual" properties in the derived classes--the inheritance structure was created to enforce a business rule that only a certain derived type can have a relationship with another entity.
Base Type:
public abstract class Process
{
private ICollection<ProcessSpecification> _specifications { get; set; }
protected Process()
{
_specifications = new List<ProcessSpecification>();
}
public Int32 Id { get; set; }
public String Description { get; set; }
public Int32 ToolId { get; set; }
public virtual Tool Tool { get; set; }
public virtual ICollection<ProcessSpecification> Specifications
{
get { return _specifications; }
set { _specifications = value; }
}
}
Derived class (no different/unique scalar properties):
public class AssemblyProcess : Process
{
private ICollection<AssemblyProcessComponent> _components;
public AssemblyProcess()
{
_components = new List<AssemblyProcessComponent>();
}
public virtual ICollection<AssemblyProcessComponent> Components
{
get { return _components; }
set { _components = value; }
}
}
Another derived type
public class MachiningProcess : Process
{
private ICollection<MachiningProcessFeature> _features;
public MachiningProcess()
{
_features = new List<MachiningProcessFeature>();
}
public virtual ICollection<MachiningProcessFeature> Features { get { return _features; } set { _features = value; } }
}
Is code-first not adding the discriminator column in the database because it doesn't see any differences between the derived classes (because of there not being any unique "non-virtual" properties)? If so, how do I get around this? If not, what are some reasons why code-first would not automatically create the discriminator column in the database? I have another TPH structure that works exactly the way it's supposed to.
DbContext:
public LineProcessPlanningContext()
: base("LineProcessPlanning")
{
}
public DbSet<Component> Components { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<Feature> Features { get; set; }
public DbSet<OperationDefinition> OperationDefinitions { get; set; }
public DbSet<PartDesign> PartDesigns { get; set; }
public DbSet<Process> Processes { get; set; }
public DbSet<ProcessPlan> ProcessPlans { get; set; }
public DbSet<ProcessPlanStep> ProcessPlanSteps { get; set; }
public DbSet<ProductionLine> ProductionLines { get; set; }
public DbSet<StationCycleDefinition> StationCycleDefinitions { get; set; }
public DbSet<StationCycleStep> StationCycleSteps { get; set; }
public DbSet<StationDefinition> StationDefinitions { get; set; }
public DbSet<UnitOfMeasurement> UnitsOfMeasurement { get; set; }
public DbSet<Tool> Tools { get; set; }
I also tried creating "dummy" properties that are unique to each derived type. Code migrations added the new properties as columns to the table, but the migration did not create a discriminator column.
I figured out the cause of this in my situation, same as yours. The base class is abstract, therefore EF won't create a TPH table for that class since it can't be instantiated. As a result of the abstract base class, EF will create tables for each of the derived classes, and therefore no need for a discriminator column.
In my case, it was acceptable to remove abstract from the base class. Once I did this, EF's TPH worked as expected.
Model:
public class Student
{
public int StudentID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Gender Gender { get; set; }
public string Address { get; set; }
}
DBContext:
public class MyContext : DbContext
{
public MyContext():base(connectionstring)
{
}
public DbSet<Student> Student { get; set; }
}
Wrapper Class:
public class StudentWrapper
{
public int StudentID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Gender Gender { get; set; }
public string Address { get; set; }
}
Implementation:
public void AddStudent()
{
using(MyContext ctx = new MyContext())
{
StudentWrapper newStudent = new StudentWrapper(); // If ever I wanted this `working`
ctx.Student.Add(newStudent);
}
}
I want to make a wrapper for my model classes instead of directly using my models in CRUD operations, is this right to do so?
IMHO,
It is not a good idea untill you want to write some custom logic in the wrappers. I think you are using your model ( or rather i would say DTO objects) for communication purpose.
If you add wrapper than you need to also map it back to your DTOs. (AutoMapper can be helpful)
So , until you have very specific reason to do this than it does not make sense to create wrapper to me. One of the scenario would be writing an application in WPF or Silverlight where you want a change aware model (i.e. Model implementing INotifyPropertyChanged Interface)
Also , if you need to extend the behavior of your model , think about the extension methods before inheritance.
I'm creating a EF5 entity model with the designer (VS2012), and used the EF5 DbContext generator as code generation item.
My model contains an entity deriving from another (not abstract).
So let's say the base entity is called BaseEntity, and the derived entity is DerivedEntity.
Now I see in the generated context class, that there is no
Public DbSet<DerivedEntity> DerivedEntities { get; set; }
defined.
Only
Public DbSet<BaseEntity> BaseEntities { get; set; }
is defined.
Is this normal ? And if yes, how do I query the derived entities in linq ?
I'm used to query like this:
using(var ctx = new EntityContainer)
{
var q = from e in ctx.DerivedEntities <-- but this is now not possible since it doesn't exist
select e;
return q.ToList();
}
Thanks for replying.
EDIT:
As requested, generated classes posted:
public partial class Scheduling
{
public int Id { get; set; }
public string Subject { get; set; }
public System.DateTime BeginDate { get; set; }
public System.DateTime EndDate { get; set; }
}
public partial class TeamScheduling : Scheduling
{
public int TeamId { get; set; }
public Nullable<int> AssignmentId { get; set; }
public virtual Team Team { get; set; }
public virtual Assignment Assignment { get; set; }
}
public partial class EntityContainer : DbContext
{
public EntityContainer()
: base("name=EntityContainer")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public DbSet<Team> Teams { get; set; }
public DbSet<Location> Locations { get; set; }
public DbSet<Country> Countries { get; set; }
public DbSet<Assignment> Assignments { get; set; }
public DbSet<ProductType> ProductTypes { get; set; }
public DbSet<AssignmentPreference> AssignmentPreferences { get; set; }
public DbSet<Scheduling> Schedulings { get; set; }
}
As you see, the EntityContainer class does not contain
public DbSet<TeamScheduling> TeamSchedulings { get; set; }
This is expected when you use inheritance the way you have. context.Schedulings contains both Scheduling objects and TeamScheduling objects. You can get the TeamScheduling objects only by asking for context.Schedulings.OfType<TeamScheduling>(). Note that you cannot meaningfully use context.Schedulings.OfType<Scheduling>() to get the others: that will also include the TeamScheduling objects.
You could alternatively try context.Set<TeamScheduling>(), but I'm not entirely sure that will work.
If your intention is to have two tables come up, say a parent Scheduling entity as well as a child TeamScheduling entity that has a foreign key back to the Scheduling entity, consider using a Table-per-Type (TPT) mapping as discussed here.
In essence, you should modify your "OnModelCreating" method to have the following code:
modelBuilder.Entity<TeamScheduling>().ToTable("TeamScheduling");
This explicitly tells EF that you want to have the TeamScheduling subclass to be represented as its own table. Querying it via LINQ would be simple as you would be able to do something like the following:
var teamScheds = context.Set<TeamScheduling>().Where(s => s.Id == 1).FirstOrDefault();