How do I custom validate collections withing MVC5 - validation

I am building an MVC5 application and I have the following viewmodels:
public class UserPartyViewModel
{
public UserPartyViewModel()
{
Entitlements = new Collection<AssignedClaims>();
}
public Guid PartyID { get; set; }
public string PartyName { get; set; }
public ICollection<AssignedClaim> AssignedClaims{ get; set; }
}
public class AssignedClaims
{
public AssignedClaims()
{
ClaimValues = new Collection<AssignedClaimValue>();
}
public string Name { get; set; }
public int Max { get; set; }
public int Min { get; set; }
public ICollection<AssignedClaimValue> ClaimValues { get; set; }
}
public class AssignedClaimValue
{
public Guid ClaimValueID { get; set; }
public string ClaimValue { get; set; }
public bool Assigned { get; set; }
}
Contained in the UserPartyViewModel will always be an assignedclaim with a name of "Security" and the assignedclaimvalue with a claimvalue of "User"
If the ClaimValue of user is Assigned then I need to validate the rest of the model. If it is not then no further validation should take place.
Within AssignedClaims there is a min and max, these are the minimum and maximum number of assignedclaimvalues that should be Assigned.
I have tried to use AttributeValidate cannot stop it validating the rest of the model.
I have also looked at the IValidatableObject interface but also can't work out how to control the validation of the child collections depending on the User claim.
What's the best way to achieve this?

Found a solution which appears to do what I want:
public class UserPartyViewModel : IValidatableObject
{
public UserPartyViewModel()
{
Entitlements = new Collection<AssignedClaims>();
}
public string AccessLevel { get; set; }
public Guid PartyID { get; set; }
public string PartyName { get; set; }
public ICollection<AssignedClaims> Entitlements { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var isUser = Entitlements.Any(c => c.Name == "Security" && c.ClaimValues.Any(v => v.Assigned == true && v.ClaimValue == "User"));
if (isUser)
{
int i = 0;
foreach (var result in Entitlements)
{
yield return result.Validate(i++);
}
}
else
{
yield return ValidationResult.Success;
}
}
}
public class AssignedClaims
{
public AssignedClaims()
{
ClaimValues = new Collection<AssignedClaimValue>();
}
public string Name { get; set; }
public string Description { get; set; }
public int Max { get; set; }
public int Min { get; set; }
public ICollection<AssignedClaimValue> ClaimValues { get; set; }
public ValidationResult Validate(int item)
{
int min = Min;
int max = (ClaimValues.Count() < Max) ? ClaimValues.Count() : Max;
int assignedCount = ClaimValues.Where(i => i.Assigned == true).Count();
if (!(min <= assignedCount && assignedCount <= max))
{
string errMessage = String.Format("{2} should have between {0} and {1} Security Claims checked.", min, max, Name);
return new ValidationResult(errMessage, new[] { string.Format("Entitlements[{0}]", item) });
}
else
{
return ValidationResult.Success;
}
}
}
The only issue I had was trying to get the error messages appearing in the correct place. In my view for assignedclaims I added:
#Html.ValidationMessageFor(model => model, "", new { #class = "text-danger" })
and passed the iteration through to the validate function on assignedclaim to ensure it was added to the correct member.

Related

Linq ORM map Object to 3 level Object

I have object like this. This include Group Question (QG), 1 group question has many Question(Q), 1 question has many answer.
public class CrmQuestionAnswer
{
public long QgId { get; set; }
public string QgName { get; set; }
public int QgMIndex { get; set; }
public int QgMdf { get; set; }
public string QgDescription { get; set; }
public long QId { get; set; }
public long QParentId { get; set; }
public string QName { get; set; }
public string QDescription { get; set; }
public int QMindex { get; set; }
public int QMdf { get; set; }
public bool IsMainQuestion { get; set; }
public bool IsTitle { get; set; }
public int QTypeId { get; set; }
public long AnswerId { get; set; }
public string AnswerName { get; set; }
public string AnswerValue { get; set; }
public int AnswerMdf { get; set; }
public int AnswerMIndex { get; set; }
public string AnswerDescription { get; set; }
public long? LinkQuestionId { get; set; }
}
I want to use Linq to map List CrmQuestionAnswer to List QuestionGroupView
public class QuestionGroupView:Title
{
public List<CrmQuestionView> Questions;
}
public class CrmQuestionView: Title
{
public long? ParentId;
public bool? IsMainQuestion;
public bool? IsTitle;
public long? LinkQuestionId;
public List<CrmAnswerView> Answers;
}
public class CrmAnswerView : Title
{
public long? LinkQuestionId;
}
Title is base class:
public class Title
{
public long Id { get; set; }
public string Name { get; set; }
public int MIndex { get; set; }
public int Mdf { get; set; }
public int Type { get; set; }
public string Description { get; set; }
}
I use this code:
public List<QuestionGroupView> GetListQuestionsAnswers(long themaId)
{
var questionAnswerDao = new CrmQuestionAnswerDao();
var questionAnswerlist = questionAnswerDao.GetByThemasId(themaId);
//map List CrmQuestionAnswer -> List QuestionGroupView: 3 level
var listquestiongroup = questionAnswerlist
.OrderBy(t => t.QgMIndex)
.ThenBy(t => t.QMindex)
.GroupBy(t => t.QgId)
.Select(GetQuestionGroup)
.ToList();
return listquestiongroup;
}
private static QuestionGroupView GetQuestionGroup(IGrouping<long, CrmQuestionAnswer> grouping)
{
var group = grouping.First();
var question = new QuestionGroupView
{
Id = group.QgId,
Name = group.QgName,
Description = group.QgDescription,
Mdf = group.QgMdf,
MIndex = group.QgMIndex,
Questions = grouping
.Select(p => new CrmQuestionView
{
Id = p.QId,
Name = p.QName,
Description = p.QDescription,
Mdf = p.QMdf,
MIndex = p.QMindex,
Type = p.QTypeId,
ParentId = p.QParentId,
IsMainQuestion = p.IsMainQuestion,
IsTitle = p.IsTitle,
Answers = grouping//**This line is wrong**
.GroupBy(g => g.QId)
.Select(GetTitle)
.ToList()
})
.ToList()
};
return question;
}
private static CrmAnswerView GetTitle(IGrouping<long, CrmQuestionAnswer> grouping)
{
var group = grouping.First();
var answer = new CrmAnswerView
{
Id = group.AnswerId,
Name = group.AnswerName,
Description = group.AnswerDescription,
MIndex = group.AnswerMIndex,
Mdf = group.AnswerMdf,
Type = group.QTypeId,
LinkQuestionId = group.LinkQuestionId,
};
return answer;
}
This is data get from server Data
My code gets right Group question (2 group) with right List question, but it gets wrong list answer from data.
Can some help me ?
Best regards

Select Foreign key data in EF

I have 2 models : Account and Task
public class Account
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Key]
public Guid UserId { get; set; }
public string UserType { get; set; }
public string Name { get; set; }
}
public class Task
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
[Key]
public Guid TaskId { get; set; }
[ForeignKey("TaskSubType")]
public Guid TaskSubTypeId { get; set; }
public virtual TaskSubType TaskSubType { get; set; }
[ForeignKey("Account")]
public Guid TaskCreator { get; set; }
public virtual Account Account { get; set; }
}
I call getTasks:
public List<TaskOverViewViewModel> GetTasks()
{
IEnumerable<Task> result = db.Tasks.AsEnumerable();
List<TaskOverViewViewModel> list = ToViewModelMapper.toViewModel(result);
return list;
}
public class ToViewModelMapper
{
internal static List<TaskOverViewViewModel> toViewModel(IEnumerable<Task> entitys )
{
List<TaskOverViewViewModel> modelList = new List<TaskOverViewViewModel>();
foreach (var entity in entitys)
{
TaskOverViewViewModel model = new TaskOverViewViewModel();
model.SubTaskName = entity.TaskSubType.Name;
model.TaskCreator = entity.Account.LoginName;
model.ToolsAccesable = entity.ToolsAccesable;
modelList.Add(model);
}
return modelList;
}
}
But it fails because i entity.TaskSubType and entity.Account is null. But if i return IEnumerable<Task> result = db.Tasks.AsEnumerable(); in the call everything works fine and i can see that Json contains all TaskSubtype and Account models.
From linq-to-entities, you can project directly to your ViewModel class.
public List<TaskOverViewViewModel> GetTasks()
{
List<TaskOverViewViewModel> result = (from t in db.Tasks
select new TaskOverViewViewModel
{
SubTaskName = t.TaskSubType.Name;
TaskCreator = t.Account.LoginName;
ToolsAccesable = t.ToolsAccesable;
}).ToList();
return result;
}
If you prefer method syntax, you can use this:
List<TaskOverViewViewModel> result = db.Tasks.Select(t => new TaskOverViewViewModel
{
SubTaskName = t.TaskSubType.Name;
TaskCreator = t.Account.LoginName;
ToolsAccesable = t.ToolsAccesable;
}).ToList();

Get data Self reference

I have a self reference model.
I want get data with linq.i want when status is ok return data.but if parent status is ok all of child return ok or pending or deleted.
how can i do this.
var model = _efComment.List(p => p.PostId == postId);
var list = model.ToList()
.Where(p => p.ComentStatus == ComentStatus.Ok)
.Where(x => x.Reply == null)
.ToList();using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using DomainModel.Classes;
namespace DomainModel
{
public class Comment : BaseFieldsTables
{
public string Content { get; set; }
public string WriterName { get; set; }
public string WriterEmail { get; set; }
public string WriterWebsite { get; set; }
public int PostId { get; set; }
[ForeignKey("PostId")]
public Post Post { get; set; }
public Comment Reply { set; get; }
public int? ReplyId { get; set; }
public ICollection<Comment> Children { get; set; }
public ComentStatus ComentStatus { get; set; }
}
}
namespace DomainModel
{
public enum ComentStatus
{
Ok = 1,
Pending = 2,
Deleted = 3
}
}

updating a record throws 'Multiplicity constraint violated.' in asp.net mvc

I am developing an application in asp.net mvc and using EF code first for my data access. Here is the model I use :
public class Culture
{
[Key()]
public int CultureID { get; set; }
[Required()]
[StringLength(250)]
public string CultureName { get; set; }
[Required()]
[StringLength(250)]
public string CultureDisplay { get; set; }
public virtual List<HomePage> HomePage { get; set; }
public virtual List<Person_Local> PersonLocal { get; set; }
}
public class Person
{
public int PersonID { get; set; }
[StringLength(250)]
public string PersonPicAddress { get; set; }
public virtual List<Person_Local> PersonLocal { get; set; }
}
public class Person_Local
{
//[NotMapped()]
[Key, Column(Order = 1)]
[ForeignKey("Person")]
public int PersonID { get; set; }
[Key, Column(Order = 2)]
[ForeignKey("Culture")]
public int CultureID { get; set; }
public string PersonName { get; set; }
public string PersonFamily { get; set; }
public string PersonAbout { get; set; }
public virtual Culture Culture { get; set; }
public virtual Person Person { get; set; }
}
I dont have any problem adding new person and personlocal to db. But when I want to update the person local, as below:
public ActionResult CreatePerson([Bind(Prefix = "Person")]Person obj,
[Bind(Prefix = "Person.PersonLocal")]IEnumerable<Person_Local> plocals)
{
string photo_guid = obj.PersonPicAddress;
if (obj.PersonID != 0)
{
Person p = da.Persons.FirstOrDefault(x => x.PersonID == obj.PersonID);
TryUpdateModel(p, "Person");
if (obj.PersonLocal[0].Person.PersonID != 0)
{
int cid = obj.PersonLocal[0].Culture.CultureID;
int pid = obj.PersonLocal[0].Person.PersonID;
Person_Local ploc =
da.Person_Locals.First(x => x.CultureID == cid && x.PersonID == pid);
//update ploc
}
da.SaveChanges();
}
}
I got following error :
Multiplicity constraint violated. The role 'Person_Local_Person_Target' of the relationship 'WebApp.Models.Person_Local_Person' has multiplicity 1 or 0..1.
Edited:
I commented
TryUpdateModel(p, "Person");
And the it seems the problem has been solved ?!! Why ?!

reference model variable to global variable value in .net mvc3

with curiosity...
i am seeking for a temporary solution that will lead to an expansions of a system side controller.
i a mvc3.net razor based project with 100+ of class file
all of the class file (model) has a system field
specific
public string u_by { get; set; }
public System.DateTime u_date { get; set; }
public System.DateTime c_date { get; set; }
public string c_by { get; set; }
public int version { get; set;
public int groupid { get; set; }
public int status { get; set; }
at the moment the useraccess control has not been build yet which in the end the useraccess controller will and suppose to fill in this variable.
i need to fixed the value for all the variable above during a form insert, update, delete
is there any where i can
create a class and put a default value to it ?
i have created a
namespace webapp.Models
{
public class sysfield
{
public string _updatedBy;
public string _createdBy;
public DateTime _updatedDate;
public DateTime _createdDate;
public int _version;
public int _groupid;
public int _status;
//Constructor
public sysfield()
{
_updatedBy = HttpContext.Current.Server.MachineName.ToString();
_createdBy = HttpContext.Current.Server.MachineName.ToString();
_updatedDate = System.DateTime.Now;
_createdDate = System.DateTime.Now;
_version = updateVersion;
_groupid = 100;
_status = 1;
}
//Property
public int updateVersion
{
get
{
return _version;
}
set
{
_version = _version + 1;
}
}
//Set Values
public string createdBy(string initialCreator)
{
if (updateVersion == 1)
{
return _createdBy = initialCreator;
}
else
{
return _createdBy = HttpContext.Current.Server.MachineName.ToString();
}
}
public DateTime createdDate(DateTime initialDate)
{
if (updateVersion == 1)
{
return _createdDate = initialDate;
}
else
{
return _createdDate = System.DateTime.Now;
}
}
}
}
now the question is how do i default it in code below, where when i insert the model
of
namespace webapp.Models
{
public partial class usr_myapp
{
public int VEHID { get; set; }
public string CARNAME { get; set; }
public string CATEGORY { get; set; }
public string TYPE { get; set; }
public string u_by { get; set; }
public System.DateTime u_date { get; set; }
public System.DateTime c_date { get; set; }
public string c_by { get; set; }
public int version { get; set; }
public int groupid { get; set; }
public int status { get; set; }
}
}
with the Controller:
Where user will fill in everything else except for the system field c_by,u_by, and etc...
// POST: /myapp/Create
[HttpPost]
public ActionResult Create(usr_myapp usr_myapp)
{
if (ModelState.IsValid)
{
db.usr_myapp.Add(usr_myapp);
db.SaveChanges();
}
return View(usr_myapp);
}
how do i default the
`
public ActionResult Create(usr_myapp usr_myapp)
{
if (ModelState.IsValid)
{
db.usr_myapp.Add(usr_myapp);
db.SaveChanges();
}
return View(usr_myapp);
}
`
where usr_myapp consist of
public int VEHID { get; set; }
public string CARNAME { get; set; }
public string CATEGORY { get; set; }
public string TYPE { get; set; }
public string u_by { get; set; }
public System.DateTime u_date { get; set; }
public System.DateTime c_date { get; set; }
public string c_by { get; set; }
public int version { get; set; }
public int groupid { get; set; }
public int status { get; set; }
the partial class, i got it from the edmx generation should i be changing all of it?
a lost man in the amazing world
You set the defaults in the constructor. Do you have a specific need for it to be a partial class?

Resources