Cannot Add Previously Inserted Object to Another Object (Entity Framework) - asp.net-mvc

I have the EF classes OAFile and Email. I am loading the emails from the server and storing in the repository. The user can then list the e-mails and "associate" them with the selected file.
The email object is previously inserted into the repository, and I want to get the count of the emails of the file.
file.Emails.Add(email)
adds the email to the file object, but it is not being saved.
file.Emails.Count
returns always 0.
The email.FileID field is saved correctly.
What am I missing? How can get the number of email by calling file.Emails.Count?
[HttpPost]
[ValidateInput(false)]
public ActionResult AssignEmail(int emailId, int assignedTo)
{
if (emailId > 0 && assignedTo > 0)
{
Email email = repository.Emails.FirstOrDefault(x => x.EmailID == emailId);
OAFile file = repository.OAFiles.FirstOrDefault(x => x.FileID == assignedTo);
if (email != null && file != null)
{
email.FileID = assignedTo;
email.AssignedByID = HttpContext.User.Identity.GetUserId();
file.Emails.Add(email);
repository.Save();
return Json(new { success = true }, JsonRequestBehavior.DenyGet);
}
else
{
return Json(new { success = false }, JsonRequestBehavior.DenyGet);
}
}
else
{
return Json(new { success = false }, JsonRequestBehavior.DenyGet);
}
}
The Email class:
public class Email
{
public Email()
{
Attachments = new HashSet<EmailAttachment>();
}
[Key]
public int EmailID { get; set; }
public string EmailIdentifier { get; set; }
public int MessageNumber { get; set; }
public string From { get; set; }
public string Subject { get; set; }
public DateTime DateSent { get; set; }
public string Body { get; set; }
public int? FileID { get; set; }
public string AssignedByID { get; set; }
public string AssignedToID { get; set; }
public string EmailType { get; set; }
public ICollection<EmailAttachment> Attachments { get; set; }
[ForeignKey("FileID")]
public virtual OAFile OAFile { get; set; }
[ForeignKey("AssignedByID")]
public virtual AppUser AssignedBy { get; set; }
[ForeignKey("AssignedToID")]
public virtual AppUser AssignedTo { get; set; }
}
and the OAFile class:
public class OAFile
{
public OAFile()
{
Services = new HashSet<Service>();
Documents = new HashSet<Document>();
Notes = new HashSet<Note>();
Forms = new HashSet<Form>();
Emails = new HashSet<Email>();
}
[Key]
public int FileID { get; set; }
[Required]
public int CompanyID { get; set; }
[Required]
[StringLength(14)]
public string OurFileName { get; set; }
[Required]
[StringLength(100)]
public string CompanyFileName { get; set; }
[Required]
public string AppUserId_Creator { get; set; }
[DisplayFormat(DataFormatString = "{0:dd.MM.yyyy}")]
public DateTime CreatedOn { get; set; }
public int ClientID { get; set; }
[ForeignKey("ClientID")]
public virtual Client Client { get; set; }
public virtual ICollection<Service> Services { get; set; }
public ICollection<Document> Documents { get; set; }
public ICollection<Note> Notes { get; set; }
public ICollection<Form> Forms { get; set; }
public ICollection<Email> Emails { get; set; }
public virtual Company Companies { get; set; }
[ForeignKey("AppUserId_Creator")]
public virtual AppUser AppUsers_Creator { get; set; }
}
EDIT: I am calling the file.Emails.Count statement below to check whether the file has any emails associated with it.
public bool IsFileEmpty(int fileId)
{
bool isFileEmpty = true;
OAFile file = repository.FindOAFile(fileId);
if (file.Services.Count > 0 || file.Documents.Count > 0
|| file.Forms.Count > 0 || file.Notes.Count > 0 || file.CCTable != null || file.AccountingTable != null
|| file.Emails.Count > 0
)
{
isFileEmpty = false;
}
return isFileEmpty;
}
EDIT 2: I am calling the IsFileEmpty() method in another controller (HomeController.cs) while populating view model for search results. The results rows display the Delete link if the file is empty.
public ActionResult FilesSearch(FileSearchViewModel viewModel)
{
var files = !string.IsNullOrWhiteSpace(viewModel.Keyword) ? repository.FindOAFiles(viewModel.Keyword) : repository.OAFiles;
var sortedFile = files.Where(x => x.IsFileOpen).OrderByDescending(x => x.CreatedOn).ToList();
sortedFile.AddRange(files.Where(x => !x.IsFileOpen).OrderByDescending(x => x.CreatedOn));
var resultsList = new List<FileSearchResultsViewModel>();
foreach (OAFile file in sortedFile)
{
var resultsViewModel = new FileSearchResultsViewModel();
resultsViewModel.oAFile = file;
resultsViewModel.isFileEmpty = IsFileEmpty(file.FileID);
resultsList.Add(resultsViewModel);
}
return PartialView("_FilesSearch", resultsList);
}

Related

AutoMapper Many to Many relationship

I'm not sure where I'm going wrong here. I want to map my classes so that there aren't extra levels in the returned values.
Models (DTOs):
public class FilmViewModel
{
public FilmViewModel() { }
public int Id { get; set; }
[Required(ErrorMessage = "Naziv filma je obavezno polje.")]
public string Naziv { get; set; }
public string Opis { get; set; }
public string UrlFotografije { get; set; }
[RegularExpression(#"^(19|20)[\d]{2,2}$", ErrorMessage = "Godina mora biti u YYYY formatu.")]
public int Godina { get; set; }
public JezikEnum Jezik { get; set; }
public int Trajanje { get; set; }
public bool IsActive { get; set; }
public List<Licnost> Licnosti { get; set; }
}
public class LicnostViewModel
{
public LicnostViewModel() { }
public int Id { get; set; }
[Required]
public string ImePrezime { get; set; }
[Required]
public bool IsGlumac { get; set; }
[Required]
public bool IsRedatelj { get; set; }
public List<Film> Filmovi { get; set; }
}
Entities:
public class Film
{
[Key]
public int Id { get; set; }
[Required]
public string Naziv { get; set; }
public string Opis { get; set; }
public string UrlFotografije { get; set; }
[RegularExpression(#"^(19|20)[\d]{2,2}$")]
public int Godina { get; set; }
public JezikEnum Jezik { get; set; }
public bool IsActive { get; set; }
public int Trajanje { get; set; }
public List<FilmLicnost> Licnosti { get; set; }
}
public class Licnost
{
[Key]
public int Id { get; set; }
[Required]
public string ImePrezime { get; set; }
[Required]
public bool IsGlumac { get; set; }
[Required]
public bool IsRedatelj { get; set; }
public List<FilmLicnost> Filmovi { get; set; }
}
public class FilmLicnost
{
[Key]
public int Id { get; set; }
[ForeignKey(nameof(Licnost))]
public int LicnostId { get; set; }
public Licnost Licnost { get; set; }
[ForeignKey(nameof(Film))]
public int FilmId { get; set; }
public Film Film { get; set; }
}
Basically Swagger already shows me what I'm returning, but I want to avoid unnecessary nesting. It's marked in the image:
I want to say that I've been looking all over SO, AutoMapper documentation etc. No answer/example finds me the solution I need. I'm either missing a Model(DTO) somewhere or there is something major wrong with my logic.
Some example links that I tried are this and this
Also here are some links I tried to get information from: link1, link2
This is what I've tried so far:
CreateMap<FilmLicnost, LicnostViewModel>()
.ForMember(dest => dest.Filmovi, dest => dest.MapFrom(x => x.Film))
.AfterMap((source, destination) =>
{
if (destination?.Filmovi == null) return;
foreach (var temp in destination.Filmovi)
{
temp.Id = source.Film.Id;
temp.IsActive = source.Film.IsActive;
temp.Jezik = source.Film.Jezik;
temp.Naziv = source.Film.Naziv;
temp.Opis = source.Film.Opis;
temp.Godina = source.Film.Godina;
temp.Trajanje = source.Film.Trajanje;
temp.UrlFotografije = source.Film.UrlFotografije;
}
});
CreateMap<FilmLicnost, FilmViewModel>()
.ForMember(dest => dest.Licnosti, dest => dest.MapFrom(x => x.Licnost))
.AfterMap((source, destination) =>
{
if (destination?.Licnosti == null) return;
foreach (var temp in destination?.Licnosti)
{
temp.Id = source.Licnost.Id;
temp.ImePrezime = source.Licnost.ImePrezime;
temp.IsGlumac = source.Licnost.IsGlumac;
temp.IsRedatelj = source.Licnost.IsRedatelj;
}
});
Also this:
CreateMap<FilmLicnost, Film>()
.ForMember(dest => dest.Licnosti, dest => dest.Ignore());
CreateMap<FilmLicnost, Licnost>()
.ForMember(dest => dest.Filmovi, dest => dest.Ignore());
Note I have already defined the mapping for Entities:
CreateMap<Film, FilmViewModel>();
CreateMap<FilmViewModel, Film>();
CreateMap<Licnost, LicnostViewModel>();
CreateMap<LicnostViewModel, Licnost>();

assign list items to model properties

MODEL
namespace CG.MyPollSurveyAdmin.Models
{
public class CompletePollSurvey
{
public long PollSurveyID { get; set; }
public string Name { get; set; }
public List<OptionData> Options { get; set; }
public List<QuestionData> QuestionDetails { get; set; }
}
public class QuestionData
{
public string QuestionName { get; set; }
public long QuestionID { get; set; }
public int OptionID { get; set; }
public string OptionType { get; set; }
public string Option_1 { get; set; }
public string Option_2 { get; set; }
public string Option_3 { get; set; }
public string Option_4 { get; set; }
public string Option_5 { get; set; }
}
}
CONTROLLER
private List<Question> GetQuestionsById(long PollSurveyId)
{
MemoryStream outMemoryStream = RESTFulServiceHelper.Instance.ExecuteGetMethod(Constants.Method_GetAllQuestions, Convert.ToString(Session[Constants.NTLoginID]));
DataContractJsonSerializer outDataContractJsonSerialize = new DataContractJsonSerializer(typeof(List<Question>));
List<Question> lstQuestions = outDataContractJsonSerialize.ReadObject(outMemoryStream) as List<Question>;
List<Question> question = lstQuestions.Where(p => p.PollSurveyID == PollSurveyId).ToList();
return question;
}
public ActionResult Help(long PollSurveyID=2)
{
if (Session[Constants.Session_IsAdmin] != null && Convert.ToBoolean(Session[Constants.Session_IsAdmin]))
{
CompletePollSurvey completePollSurvey = new CompletePollSurvey();
List<Question> question = GetQuestionsById(Convert.ToInt64(PollSurveyID));
return View(completePollSurvey);
}
else
{
return RedirectToAction("Login");
}
}
Here is the model and controller of my program. Till now I'm getting All the questions for poll id=2 but I'm having difficulty in retrieving element from Question List and assign it to Model List elements(or list to list assignment).
For e.g I have 5 questions for Poll=2 and in each question there are 5 options

ListBoxFor returns null values when submitting the page

I'm having problems with the ListBoxFor... It works fine by the Get request, it loads the list and pre-selects the selected values but when the user edits the form and submits the page, it returns null; it does not return the selected values... Can anyone help? I'm very new to programming in general and I can't figure this out.
This is my ProjectDetailsViewModel:
public class ProjectDetailsViewModel
{
public string ReturnMessage { get; set; }
public Project Project { get; set; }
public List<ProjSubIndustryMaster> SubIndustries { get; set; }
public List<ProjIndustryMaster> Industries { get; set; }
public List<Potential> Potentials { get; set; }
public List<ProjectCategoryMaster> Categories { get; set; }
public List<ProjectResources> ProjectManagers { get; set; }
public List<ProjectResources> SalesManagers { get; set; }
public List<ProjectOriginationMaster> OriginationList { get; set; }
public List<MasterProject> MasterProjects { get; set; }
public List<ProjectStatusMaster> ProjectStatusList { get; set; }
public List<PrimaryMaterials> PrimaryMaterialList { get; set; }
public List<ProjectMaterialMaster> MaterialList { get; set; }
public List<PrimaryServices> PrimaryServiceList { get; set; }
public List<ServiceCodeMaster> ServiceList { get; set; }
public List<PrimarySources> PrimarySourceList { get; set; }
public List<SourceCodeMaster> SourceList { get; set; }
public List<ProjTechnologyTypeMaster> TechnologyTypesList { get; set; }
public List<PrimaryTargets> PrimarytargetList { get; set; }
public List<TargetCodeMaster> TargetCodeList { get; set; }
public List<ProjectTypeMaster> ProjectTypesList { get; set; }
public List<ProjectComment> Comments { get;set; }
public List<string> SelectedServices
{
get
{
var serviceList1 = Project?.ProjectPricings?.Where(x => x.ProjectId == Project.Id && !string.IsNullOrWhiteSpace(x.ServiceCode))
.Select(x => x.ServiceCode)
.ToList();
var serviceList2 = Project?.Services?.Select(x => x.ProjServiceCode).ToList();
var serviceList = new List<string>();
if (serviceList1 != null) serviceList.AddRange(serviceList1);
if (serviceList2 != null) serviceList.AddRange(serviceList2);
return serviceList;
}
}
}
}
just for clarity purposes: I'm loading the listBox with data taken from a Master(look-up)table so the user can have "all" the options available to choose from for example: ProjectMaterialMaster table which has 2 columns- Id and Material... In other words, the selected values are not taken from the same table as the data from the listBox. The tables look like this:
ProjectMaterialMasterId MaterialCode
1 A
2 C
...
ProjectMaterialId ProjectId MaterialCode
1 4118 C
2 5342 C
3 5647 A
4 4118 B
...
The 1st table has all the materials available and the second table is a mapping table and connects all the projects to their associated material...
This is my View:
<td class="control-input">
#{
var materials = Model.Project?.Materials.Select(x=>x.ProjMaterialCode);
}
#Html.ListBoxFor(m => materials, new MultiSelectList(Model.MaterialList, "ProjMaterialCode", "ProjMaterialCode", materials), new {#class = "listbox"})
</td>
This is the controller:
[HttpPost]
public ActionResult UpdateProjectView( ProjectDetailsViewModel projectViewModel)
{
if (!ModelState.IsValid)
{
projectViewModel.ReturnMessage = #"Error! Update Failed.";
return GetProjectView(projectViewModel.ReturnMessage, projectViewModel.Project.Id);
}
if (projectViewModel.Project.Id != null)
{
var success = ProjectDataAccess.UpdateProject(projectViewModel.Project);
projectViewModel.ReturnMessage = success ? #"Project Updated Successfully" : #"Error! Update Failed";
}
else if(projectViewModel.Project.Id == null)
{
var success = ProjectDataAccess.AddProject(projectViewModel.Project);
projectViewModel.ReturnMessage = success ? #"Project Added Successfully" : #"Error! Insert Failed";
}
return GetProjectView(projectViewModel.ReturnMessage, projectViewModel.Project.Id);
}
m => materials
should be
m => m.materials

How create view for show cookie's info in asp.net mvc using razor?

I'm developing an online store using asp.net mvc 5 and I used cookie for add goods to cart . I want to have a page to show selected items (in cookie) and I don't know how do it, I just wrote an action result for it named Basket . I should use #model List<BasketVM> in my view but when don't know how ?!
could anyone help me please ?
Thanks
GoodController
[HttpGet]
public ActionResult Basket()
{
GoodDetailsRepositories blGoodDetails = new GoodDetailsRepositories();
List<BasketVM> listBasket = new List<BasketVM>();
List<HttpCookie> lst = new List<HttpCookie>();
for (int i = Request.Cookies.Count - 1; i >= 0; i--)
{
if (lst.Where(p => p.Name == Request.Cookies[i].Name).Any() == false)
lst.Add(Request.Cookies[i]);
}
foreach (var item in lst.Where(p => p.Name.StartsWith("NishtmanCart_")))
{
listBasket.Add(new BasketVM {
GoodDetails = blGoodDetails.Find(Convert.ToInt32(item.Name.Substring(13))), Count =Convert.ToInt32(item.Value) });
}
return View(listBasket);
}
BasketVM.cs
public class BasketVM
{
public NP1.Models.GoodDetail GoodDetails { get; set; }
public int Count { get; set; }
}
GoodDetails.cs
public partial class GoodDetail
{
public GoodDetail()
{
this.FactorItems = new HashSet<FactorItem>();
}
public int DetailsGoodID { get; set; }
public int FKSubGoods { get; set; }
public string NishtmanCode { get; set; }
public string DetailsColor { get; set; }
public string DetailsExist { get; set; }
public long DetailsNowPrice { get; set; }
public Nullable<long> DetailsPrePrice { get; set; }
public string DetailsName { get; set; }
public string DetailsLeatherType { get; set; }
public string DetailsWeight { get; set; }
public string DetailsSize { get; set; }
public string DetailsProducer { get; set; }
public string DetailsExtraInfo { get; set; }
public string DetailsURL { get; set; }
public string DetailsKeyWords { get; set; }
public string DetailsTags { get; set; }
public int DetailsLike { get; set; }
public int DetailsDisLike { get; set; }
public string DetailsImage1 { get; set; }
public string DetailsSmallImage1 { get; set; }
public string DetailsImage2 { get; set; }
public string DetailsSmallImage2 { get; set; }
public string DetailsImage3 { get; set; }
public string DetailsSmallImage3 { get; set; }
public string DetailsImage4 { get; set; }
public string DetailsSmallImage4 { get; set; }
public virtual SubGood SubGood { get; set; }
public virtual ICollection<FactorItem> FactorItems { get; set; }
}
Add to cart code
public ActionResult AddToCart (int Id , int Count)
{
try
{
if (Request.Cookies.AllKeys.Contains("NishtmanCart_" + Id.ToString()))
{
//Edit cookie
var cookie = new HttpCookie("NishtmanCart_" + Id.ToString(), (Convert.ToInt32(Request.Cookies["NishtmanCart_" + Id.ToString()].Value) + 1).ToString());
cookie.Expires = DateTime.Now.AddMonths(1);
cookie.HttpOnly = true;
Response.Cookies.Set(cookie);
}
else
{
//Add new cookie
var cookie = new HttpCookie("NishtmanCart_" + Id.ToString(), Count.ToString());
cookie.Expires = DateTime.Now.AddMonths(1);
cookie.HttpOnly = true;
Response.Cookies.Add(cookie);
}
List<HttpCookie> lst = new List<HttpCookie>();
for (int i = 0; i < Request.Cookies.Count; i++ )
{
lst.Add(Request.Cookies[i]);
}
bool isGet = Request.HttpMethod == "GET";
int CartCount = lst.Where(p => p.Name.StartsWith("NishtmanCart_") && p.HttpOnly != isGet).Count();
return Json(new MyJsonData()
{
Success = true,
Script = MessageBox.Show("Good added successfully", MessageType.Success).Script,
Html = "cart items (" + CartCount.ToString() + ")"
}
);
}
catch(Exception)
{
return Json(new MyJsonData()
{
Success = false,
Script = "alert('Good didn't add');",
Html = ""
}
);
}
}
with what name you are saving the cookies you can retrieve like this let say userid u want to get rest what you have wriiten will work:
if (this.ControllerContext.HttpContext.Request.Cookies.AllKeys.Contains("Userid"))
{
HttpCookie cookie = this.ControllerContext.HttpContext.Request.Cookies["Userid"];
// retrieve cookie data here
}
how to call in view :
Viewbag.userid = #Request.Cookies["Userid"].value
In order to read a cookie client-side it needs to be created with the HttpOnly flag set to false.
Please go thorugh the below already asked question.
MVC Access stored cookie

MVC Code- or Model First

Most of the tutorials for MVC with Entity Framework are centered around Code-First, where you write classes for generating the model. This gives the advantage of control and Migrations, but I think it lack overview. I would therefore prefer to create the model using the graphical designer, but I cannot see how or if data migrations work in this context. It seems, that when I change the model (with data in the database), all the data is deleted in all tables.
Is there a way around this?
How can I do validation when using Model-First? Partial classes?
you may use the global validation beside mvc validation
example :
public class ValidationCriteria
{
public ValidType Type { get; set; }
public ValidRange Range { get; set; }
public ValidFormat Format { get; set; }
public ValidIsNull IsNull { get; set; }
public ValidCompare Compare { get; set; }
public ValidDB DB { get; set; }
public string Trigger { get; set; }
public Dictionary<string, ValidationCriteria> Before { get; set; }
public string After { get; set; }
public class ValidDB
{
public string functionName { get; set; }
public object[] param { get; set; }
public object functionClass { get; set; }
public string msg { get; set; }
public bool check = false;
}
public class ValidCompare
{
public string first { get; set; }
public string second { get; set; }
public string compareOperator { get; set; }
public string compareValue { get; set; }
public string msg { get; set; }
public bool check = false;
}
public ValidationCriteria()
{
this.Range = new ValidRange();
this.Format = new ValidFormat();
this.IsNull = new ValidIsNull();
this.Type = new ValidType();
this.Compare = new ValidCompare();
this.DB = new ValidDB();
this.Trigger = "blur";
this.Before = new Dictionary<string, ValidationCriteria>();
this.After = "";
}
public class ValidType
{
// checking element is integer.
public bool isInt { get; set; }
// checking element is decimal.
public bool isDecimal { get; set; }
public string msg { get; set; }
public bool check = false;
}
public class ValidRange
{
public long min { get; set; }
public long max { get; set; }
public string msg { get; set; }
public bool check = false;
}
public class ValidFormat
{
public bool isEmail { get; set; }
public string regex { get; set; }
public string msg { get; set; }
public bool check = false;
}
public class ValidIsNull
{
public string nullDefaultVal { get; set; }
public string msg { get; set; }
public bool check = false;
}
}
Meanwhile you may use validation part in your controller
Example :
private bool validateMaintainanceManagement(MaintainanceCRUD.Maintainance model, bool edit = false, bool ServerValidation = true)
{
bool ValidModel = false;
Dictionary<string, ValidationCriteria> validCriteria = new Dictionary<string, ValidationCriteria>();
#region maintainTitle Criteria
ValidationCriteria maintainTitle = new ValidationCriteria();
maintainTitle.IsNull.msg = Resources.Home.ErrmaintainTitle;
maintainTitle.IsNull.check = true;
maintainTitle.IsNull.nullDefaultVal = "-1";
//maintainTitle.Trigger = "change"; // this may trigger if you are using dropdown
validCriteria.Add("maintainTitle", maintainTitle);
#endregion

Resources