I am creating a ASP.net MVC web app and trying to add validation attributes to a ClientsTbl.cs file I have generated from a SQL server using entity framework. I have done scaffolding and created the view and the controller for the Table(Model), but for some reason the scaffold did not recognize the primary key column as a primary key. On top of that it will not let me add attributes in []. I can't even change the field description that appears above the views form text box. How do I do the above in the following class?
namespace Testit.Models
{
using System;
using System.Collections.Generic;
public partial class ClientsTbl
{
public ClientsTbl()
{
this.ProgramClientTbls = new HashSet<ProgramClientTbl>();
}
public int id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int CenterId { get; set; }
public string MiddleName1 { get; set; }
public string MiddleName2 { get; set; }
public System.DateTime DateAdded { get; set; }
public virtual CenterTbl CenterTbl { get; set; }
public virtual ICollection<ProgramClientTbl> ProgramClientTbls { get; set; }
}
}
You can create a metadata class to do that. For example, if Id, FirstName, and LastName are required fields, you can create a new class like below.
public class ClientsTblMetadata
{
[Required()]
public int Id { get; set; }
[Required()]
public string FirstName { get; set; }
[Required()]
public string LastName { get; set; }
}
Then you need to add a new partial class with a MetadataType attribute. Please make sure that this class is located under the same namespace, otherwise it won't work.
namespace Testit.Models
{
[MetadataType(typeof(ClientsTblMetadata))] // you need this line of code.
public partial class ClientsTbl
Related
I am trying to create a ASP.NET application, and am using DataAnnotations in the Entity Class Models for more readable display names:
In my ApplicationDomain Project
public class Car{
public int Id { get; set; }
[Display(Name = "Make of Car")]
public string Make { get; set; }
[Display(Name = "Year of Purchase")]
public int PurchaseYear { get; set; }
}
When I then use this as the model for my views, everything is displayed as expected.
But when I use a view model, I then have to add the Annotations again as the Display Name I initially added to Car is not 'Inherited' to the View Models based on it.
In my WebMVC Project
public class EditCarViewModel{
[Display(Name = "Make of Car")]
public string Make { get; set; }
[Display(Name = "Year of Purchase")]
public int PurchaseYear { get; set; }
}
The same for the create, index and any other views that use a viewmodel and not the Car Class.
Is there anyway to have the annotations that are in the initial entity class model inherited / propagated up, into the related view models so I'm not having to do this in multiple places?
I think this will be even more of an issue if I then try to add a different UI project. e.g. a desktop application in addition to the WebMVC.
It would be ideal if the labels for both could be based on the definitions in the ApplicationDomain Project.
You can try creating a new metadata class and apply it to your others.
[MetadataType(typeof(CarModelMetaData))]
public class EditCarViewModel{
public string Make { get; set; }.
public int PurchaseYear { get; set; }
}
[MetadataType(typeof(CarModelMetaData))]
public class CreateCarViewModel{
public string Make { get; set; }
public int PurchaseYear { get; set; }
}
public class CarModelMetaData{
[Display(Name = "Make of Car")]
public string Make { get; set; }
[Display(Name = "Year of Purchase")]
public int PurchaseYear { get; set; }
}
There is no way of propagating annotation text from one class to another.
But if you just want to keep the same text in one place, you can create constants and use them this way:
public static class DisplayConstants
{
public const string Make = "Make of Car";
public const string PurchaseYear = "Year of Purchase";
}
public class EditCarViewModel{
[Display(Name = DisplayConstants.Make)]
public string Make { get; set; }
[Display(Name = DisplayConstants.PurchaseYear)]
public int PurchaseYear { get; set; }
}
public class Car
{
public int Id { get; set; }
[Display(Name = DisplayConstants.Make)]
public string Make { get; set; }
[Display(Name = DisplayConstants.PurchaseYear)]
public int PurchaseYear { get; set; }
}
Note that this way you can name properties in EditCarViewModel and Car whatever way you like, no restriction on consistent naming.
I am using EF 6 in Visual Studio 2013. I want to get matching records from a Parent table on behalf of foreign key from Child table.
I have following line of code
var record = db.ChannelFees.Include(x =>x.SubSource).ToList();
Here ChannelFees is the child table in which SubSourceId is foreign key from
SubSource(Parent Table).
Channel Fee Class Looks Like:
using System;
using System.Collections.Generic;
public partial class ChannelFee
{
public virtual SubSource SubSource { get; set; }
public int SubSource_id { get; set; }
public double Fee { get; set; }
public int Id { get; set; }
}
and the SubSource Class
using System;
using System.Collections.Generic;
public partial class SubSource
{
public int Id { get; set; }
public string Description { get; set; }
public string MapName { get; set; }
}
But I am getting the following exception.
A specified Include path is not valid. The EntityType 'FinancialManagmentModel.ChannelFee' does not declare a navigation property with the name 'SubSource'.
What is wrong with it?
I think it should be:
public virtual ICollection<SubSource> SubSource;
You could try with this:
public partial class ChannelFee
{
public virtual ICollection<SubSource> SubSource { get; set; } // Just to enable lazy load
public int Id { get; set; }
public string Description { get; set; }
public string MapName { get; set; }
}
public partial class SubSource
{
public int Id { get; set; }
public string Description { get; set; }
public string MapName { get; set; }
public virtual ChannelFee ChannelFee {get; set; } // Navigation property
}
And usually I also add a Mapping in the context (you can achieve the same result with configuration attributes)
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<SubSource>().HasRequired(t => t.ChannelFee)
.WithMany(t => t.SubSource);
}
Simplest way to solve the problem is to declare a navigation property with the name 'SubSource'. through Annotations
public partial class ChannelFee
{
[ForeignKey("SubSource_id")]
public virtual SubSource SubSource { get; set; }
public int SubSource_id { get; set; }
}
I have resolved the issue at my own. Actually the EF was not generating navigation property in the Model on the behalf of Foreign Key Constraint which I created in SQL, that is why error was occuring.
So I simply deleted the Model and added it again. Problem was solved.
I have an application that can contain a minimum of one "person" up to a maximum of fours "persons". I am using view models and manually mapping in the controller to the domain model.
I am completely lost as to how to include more than one "person" in the app. I've read up on using for but can't wrap my head around it.
Right now, I am just adding the data from the "person" class manually such that
Code:
public class SomeClass
{
public Guid SomeClassId {get; set;}
public string BorrowerFirst { get; set; }
public string BorrowerMI { get; set; }
public string BorrowerLast { get; set; }
public Suffix? BorrowerSuffix { get; set; }
... some more fields ...
}
and so on in the master class.
What I'd like to do is use a class such as:
Code:
public class Applicant
{
public string BorrowerFirst { get; set; }
public string BorrowerMI { get; set; }
public string BorrowerLast { get; set; }
public Suffix? BorrowerSuffix { get; set; }
}
can be reused in another class multiple times.
How can I separate that to strip that and instead use a named class consisting of first, middle and last names and allowing up to four "person" instances in my master class?
Have you tried inheritance?
public class Person
{
public Guid SomeClassId {get; set;}
public string BorrowerFirst { get; set; }
public string BorrowerMI { get; set; }
public string BorrowerLast { get; set; }
public Suffix? BorrowerSuffix { get; set; }
}
and the Applicant class:
public class Applicant : Person
{
//Only extra properties and methods here.
public string FullName
{
get
{
return this.BorrowerFirst + " " + this.BorrowerMI + " " + this.BorrowerLast;
}
}
}
You can then have a vendor as well:
public class Vendor: Person
{
//Only extra properties and methods here.
}
I am working on ASP.NET MVC project with EF6 with Database First. I am trying to use Redis server to cache frequently used objects.
But i am getting problem in saving related entities (parent-child). For example following Author and Author_Book classes are parent-child and referencing to each other (Foreign-Key constraint in RDBMS)
public partial class Author
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Author_Book> Author_Book { get; set; }
}
public partial class Author_Book
{
public int Id { get; set; }
public int AuthorId { get; set; }
public string Title { get; set; }
public virtual Author Author { get; set; }
}
public partial class Customer
{
public int ID { get; set; }
public string CustomerName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
Querying and trying to store query result to Redis server as below
using (EFTestContext db = new EFTestContext())
{
var data = db.Authors.ToList();
redisClient.Set<List<Author>>("author", data);
}
Above line redisClient.Set.. resulting following Exception
An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll
However if i store Customer entity (which doesn't have child entities) into Redis server it work fine
using (EFTestContext db = new EFTestContext())
{
var customers = db.Customers.ToList();
redisClient.Set<List<Customer>>("customers", customers);
}
So my question is how to store complete entity (with childs) into redis server?
I followed [DataContract] / [DataMember] approach (As #oferzelig mentioned in comment). It is working fine and no longer raising that exception. I am describing it here so it could help someone else.
EF Database-first by default does not add [DataContract] / [DataMember] attributes, we need to modify T4 template for it. I did following modifications in Model template Model1.tt.
Added [DataContract] attribute before the line
<#=codeStringGenerator.EntityClassOpening(entity)#>
now it looks like
[DataContract]
<#=codeStringGenerator.EntityClassOpening(entity)#>
Added [DataMember] attribute before line
<#=codeStringGenerator.Property(edmProperty)#>
and it looks like
[DataMember]
<#=codeStringGenerator.Property(edmProperty)#>
We also need to generate [DataMember] attribute for one-to-many relationships (e.g. public virtual ICollection<Author_Book> Author_Book { get; set; } in question) but NOT for one-to-one (e.g. public virtual Author Author { get; set; } in question). To achieve it i added a new function in CodeStringGenerator class
public string NavigationProperty_NeedDataMember(NavigationProperty navProp)
{
return string.Format(
CultureInfo.InvariantCulture,
"{0}",
navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("[DataMember]") : ""
);
}
and called it just before the line
<#=codeStringGenerator.NavigationProperty(navigationProperty)#>
as below
<#=codeStringGenerator.NavigationProperty_NeedDataMember(navigationProperty)#>
<#=codeStringGenerator.NavigationProperty(navigationProperty)#>
And finally modified UsingDirectives procedure to add System.Runtime.Serialization, as below
public string UsingDirectives(bool inHeader, bool includeCollections = true)
{
return inHeader == string.IsNullOrEmpty(_code.VsNamespaceSuggestion())
? string.Format(
CultureInfo.InvariantCulture,
"{0}using System;{1}" +
"{2}" +
"{3}",
inHeader ? Environment.NewLine : "",
includeCollections ? (Environment.NewLine + "using System.Collections.Generic;") : "",
includeCollections ? (Environment.NewLine + "using System.Runtime.Serialization;") : "",
inHeader ? "" : Environment.NewLine)
: "";
}
That all.
Now it is generating following classes and i no need to edit classes manually after each update.
[DataContract]
public partial class Author
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public virtual ICollection<Author_Book> Author_Book { get; set; }
}
[DataContract]
public partial class Author_Book
{
[DataMember]
public int Id { get; set; }
[DataMember]
public int AuthorId { get; set; }
[DataMember]
public string Title { get; set; }
public virtual Author Author { get; set; }
}
Hope it will help someone else.
I am trying to figure out how AutoMapper works in creating a map from the domain model to the view model with a complex collection.
Within my domain model (Search.Domain) ,
I have the following:
namespace Search.Domain.Model
{
public class Result
{
public int SearchTime { get; set; }
public List<ResultDetails> Context { get; set; }
}
public class ResultDetails
{
public string Entity { get; set; }
public string Jurisdiction { get; set; }
public DateTime DateReported { get; set; }
public string Description { get; set; }
public DateTime DateEntered { get; set; }
public string AssociatedLink { get; set; }
public int Relevance { get; set; }
}
}
with the MVC project (Search.WebUI) I have the following:
namespace Search.WebUI.Models
{
public class ResultViewModel
{
public int SearchTime { get; set; }
public List<ResultDetails> Context { get; set; }
}
public class ResultDetails
{
public string Entity { get; set; }
public string Jurisdiction { get; set; }
public DateTime DateReported { get; set; }
public string Description { get; set; }
public DateTime DateEntered { get; set; }
public string AssociatedLink { get; set; }
public int Relevance { get; set; }
}
}
Within the controller (HomeController.cs)
namespace Search.WebUI.Controllers
{
public class HomeController : Controller
{
private ISearchResultManager sr = new ResultManager();
public ActionResult Index()
{
ResultViewModel searchresults;
var results = sr.GetSearchResults(5);
Mapper.CreateMap<Search.Domain.Model.Result, ResultViewModel>();
searchresults = Mapper.Map<Search.Domain.Model.Result, ResultViewModel>(results);
return View("Home", searchresults);
}
}
}
The error message that is being generated when run is:
Missing type map configuration or unsupported mapping.
Mapping types:
ResultDetails -> ResultDetails
Search.Domain.Model.ResultDetails -> Search.WebUI.Models.ResultDetails
Destination path:
ResultViewModel.Context.Context.Context0[0]
Source value:
Search.Domain.Model.ResultDetails
In looking at this it appears that the nested List<ResultDetails> is causing an issue but I don't know what I am supposed to do to handle this type of mapping.
Is it correct to go all the way back into the domain for reference to the type? This seems as if I am pulling the domain into the UI which I would not want to do?
Is there another option for mapping domain models to view models in the UI? Basically I was hoping to have a view model within the UI that I could extend beyond the domain model for UI purposes and not put a reference to the domain model.
I am new to autoMapper so this entire thing may be wrong? I would appreciate any suggestions or guidance.
AutoMapper doesn't look at all potential child mapping when mapping a containing class. You need to explicitly add a mapping for the ResultDetails as well:
Mapper.CreateMap<Search.Domain.Model.Result.ResultDetails,
Search.WebUI.Models.ResultDetails>();