cant insert complex object to database using entity frame work - asp.net-mvc-3

I am developing an asp.net mvc application, which has these enity classes:
public class Person
{
public int PersonID { get; set; }
public string PersonPicAddress { get; set; }
public virtual List<Person_Local> PersonLocal { get; set; }
}
public class Person_Local
{
public int PersonID { get; set; }
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; }
}
public class Culture
{
public int CultureID { get; set; }
[Required()]
public string CultureName { get; set; }
[Required()]
public string CultureDisplay { get; set; }
public virtual List<HomePage> HomePage { get; set; }
public virtual List<Person_Local> PersonLocak { get; set; }
}
I defined an action with [Httppost] attribute, which accepts complex object from a view.
Here is the action :
[HttpPost]
public ActionResult CreatePerson([Bind(Prefix = "Person")]Person obj)
{
AppDbContext da = new AppDbContext();
//Only getting first PersonLocal from list of PersonLocals
obj.PersonLocal[0].Person = obj;
da.Persons.Add(obj);
da.SaveChanges();
return Jsono(...);
}
But when it throws error as below :
Exception:Thrown: "Invalid column name 'Culture_CultureID'." (System.Data.SqlClient.SqlException)
A System.Data.SqlClient.SqlException was thrown: "Invalid column name 'Culture_CultureID'."
And the insert statement :
ADO.NET:Execute Reader "insert [dbo].[Person_Local]([PersonID], [PersonName], [PersonFamily], [PersonAbout], [Culture_CultureID])
values (#0, #1, #2, #3, null)
select [CultureID]
from [dbo].[Person_Local]
where ##ROWCOUNT > 0 and [CultureID] = scope_identity()"
The command text "insert [dbo].[Person_Local]([PersonID], [PersonName], [PersonFamily], [PersonAbout], [Culture_CultureID])
values (#0, #1, #2, #3, null)
select [CultureID]
from [dbo].[Person_Local]
where ##ROWCOUNT > 0 and [CultureID] = scope_identity()" was executed on connection "Data Source=bab-pc;Initial Catalog=MainDB;Integrated Security=True;Application Name=EntityFrameworkMUE", building a SqlDataReader.
Where is the problem?
Edited:
Included EntityConfigurations Code:
public class CultureConfig : EntityTypeConfiguration<Culture>
{
public CultureConfig()
{
HasKey(x => x.CultureID);
Property(x => x.CultureName);
Property(x => x.CultureDisplay);
ToTable("Culture");
}
}
public class PersonConfig : EntityTypeConfiguration<Person>
{
public PersonConfig()
{
HasKey(x => x.PersonID);
Property(x=>x.PersonPicAddress);
ToTable("Person");
}
}
public class Person_LocalConfig : EntityTypeConfiguration<Person_Local>
{
public Person_LocalConfig()
{
HasKey(x => x.PersonID);
HasKey(x => x.CultureID);
Property(x=>x.PersonName);
Property(x => x.PersonFamily);
Property(x => x.PersonAbout);
ToTable("Person_Local");
}
}

Try to remove fields CultureID and PersonID from Person_Local class. Because you already has field Person and Culture

It looks like your schema is out of sync with your model. Make sure you understand EF Code first schema update features, which are described in this blog. If you need more sophisticated schema migration, there are some other approaches in answers to this question.

Related

How to configure AutoMapper for list of sub object, and how to use ProjectTo<> in query?

I have a model Template with List<Symbol> symbols, and an equivalent ViewModel TemplateJS with List<SymbolJS>. When I query for a Template, ProjectTo<TemplateJS> seems to throw an Exception and I'm not sure why.
Exception: "Argument types do not match"
I would also like to Include Symbol in my query but I'm not exactly sure how to map that object as well. Would this need be done in a separate query?
Any help is appreciated! Thanks!
Models :
public class Template
{
public int Id { get; set; }
public string Name { get; set; }
public List<Exercise> Exercises { get; set; }
public List<Symbol> Symbols { get; set; }
}
public class Symbol
{
public int Id { get; set; }
public int TemplateId { get; set; }
public Template Template { get; set; }
public char Letter { get; set; }
public string ImgSource { get; set; }
}
public class TemplateJS
{
public int Id { get; set; }
public string Name { get; set; }
public List<SymbolJS> Symbols { get; set; }
}
public class SymbolJS
{
public char Letter { get; set; }
public string ImgSrc { get; set; }
}
AutoMapper :
CreateMap<Template, TemplateJS>()
.ReverseMap();
CreateMap<Symbol, SymbolJS>()
.ReverseMap();
Query :
public async Task<TemplateJS> GetTemplateAsync(int Id)
{
try
{
var q = await _dbContext.Template
// .Include(x => x.Symbols)
.Where(x => x.Id == Id)
.ProjectTo<TemplateJS>(_mapper.ConfigurationProvider)
.SingleOrDefaultAsync();
return q;
}
catch (Exception e)
{
throw e;
}
}

Trouble mapping to DTOs with LINQ

i've been working with DTOs lately and am unable to determine the issue that this code is having.
I'm mapping Genre names and Movie names to a GenreMovieDto. Visual Studio doesn't show any errors (red lines etc) but when the code is run I get the following:
$exception {"The specified type member 'Movies' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported."} System.NotSupportedException
My code is the following:
public class Genre
{
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<Movie> Movies { get; set; }
}
public class Movie
{
public int Id { get; set; }
public string Name { get; set; }
public string AgeRating { get; set; }
public int NumberInStock { get; set; }
public Genre Genre { get; set; }
}
public class GenreMovieDto
{
public string GenreName { get; set; }
public IEnumerable<Movie> Movies { get; set; }
}
And my API call:
public IEnumerable<GenreMovieDto> GetGenresWithMovies()
{
var genresWithMovies = _context.Genres
.Include(m => m.Movies)
.Select(x => new GenreMovieDto
{
GenreName = x.Name,
Movies = x.Movies <<<<< CRASHES HERE
})
.ToList();
return genresWithMovies;
}
Any thoughts ? Any and all suggestions / criticism is welcome :P I'm here to learn.
Thanks in advance
You can do like this (EF doesn't support IEnumerable<...> type member):
public class Genre
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<Movie> Movies { get; set; }
}

MVC Query expressions over source type 'dynamic' or with a join sequence of type 'dynamic' are not allowed

I am trying to get this expression working in my Razor file:
<span>#($" ({string.Join(", ", from o in comment.CommentStaff.StaffOffices select o.Office.OfficeOrganizationCd)})")</span>
But it says "Query expressions over source type 'dynamic' or with a join sequence of type 'dynamic' are not allowed" in the red squiggly in the Razor and the Developer exception page.
Here is my model (#model CommentVM) coming down to the Razor from the controller action:
public class CommentVM
{
public int AuditId { get; set; }
public string Comment { get; set; }
public IEnumerable<Comment> Comments { get; set; }
}
Here is the Controller Action (actually this is coming from the Invoke method in a component. But this shouldn't really make a difference).
public IViewComponentResult Invoke(int auditId)
{
IQueryable<Comment> comments = _commentRepo.Comments.Include(c => c.CommentStaff).ThenInclude(c => c.StaffOffices)
.Where(c => c.CommentAuditId == auditId)
.OrderByDescending(c => c.CommentDate).Take(3);
CommentVM commentVM = new CommentVM
{
AuditId = auditId,
Comments = comments
};
return View(commentVM);
}
The Comments Repo returns an IQueryable of Comment objects.
The Comment POCO looks like this:
[Table("comment")]
public class Comment
{
[Key]
[Column("comment_id")]
public int CommentId { get; set; }
[Column("comment_type_cd")]
public string CommentTypeCd { get; set; }
[Column("comment_audit_id")]
public int? CommentAuditId { get; set; }
[Column("comment_finding_id")]
public int? CommentFindingId { get; set; }
[Column("comment_recommend_id")]
public int? CommentRecommendId { get; set; }
[Column("comment_action_item_id")]
public int? CommentActionItemId { get; set; }
[Column("comment_acd_id")]
public int? CommentAcdId { get; set; }
[Column("comment_pdl_id")]
public int? CommentPdlId { get; set; }
[Column("comment_cost_nm")]
public string CommentCostNm { get; set; }
[Required]
[Column("comment_tx")]
public string CommentText { get; set; }
[Column("comment_dt")]
public DateTime CommentDate { get; set; }
#region Navigation Properties
[Column("comment_staff_id")]
public short CommentStaffId { get; set; }
[ForeignKey("CommentStaffId")]
public Staff CommentStaff { get; set; }
#endregion
}
So CommentStaff is a navigation property to a Staff object which has a bridge table POCO called StaffOffices for a many to many relationship between Staff and Office.
Here is the bridge table POCO:
[Table("staff_office")]
public class StaffOffice
{
[Column("staff_office_staff_id")]
public short ID { get; set; }
public Staff Staff { get; set; }
[Column("staff_office_office_id")]
public short OfficeID { get; set; }
public Office Office { get; set; }
}
I am trying to get this:
<span>#($" ({string.Join(", ", from o in comment.CommentStaff.StaffOffices select o.Office.OfficeOrganizationCd)})")</span>
or this:
#{
StringBuilder sb = new StringBuilder();
foreach(var o in comment.CommentStaff.StaffOffices)
{
sb.Append(o.Office.OfficeOrganizationCd);
}
}
<span>#sb.ToString()</span>
It's a partial view. I needed to include the model definition of the parent Razor file:
#model CommentVM

Trying to Populate ViewModel List from Linq query MVC "List doesn't contain definiton for ..."error"

I am (trying to) build a multiple choice test application that will pass a list of multiple choice questions (select lists) from the controller to a view.
Then populate the view using a foreach loop, post the answers back to the controller, check them and increment the score for each correct answer and then update the db.
I am trying to populate the view model list using a Linq query (to keep my controller thin, I am doing this via a method in my Service layer).
Models
Questions (db first)
namespace AccessEsol.Models
{
using System;
using System.Collections.Generic;
public partial class Question
{
public Question()
{
this.ExamDets = new HashSet<ExamDet>();
}
public int QuID { get; set; }
public string Text1 { get; set; }
public string Text2 { get; set; }
public string CorrectAnswer { get; set; }
public string Foil1 { get; set; }
public string Foil2 { get; set; }
public string Foil3 { get; set; }
public string Level_ { get; set; }
public string GrammarPoint { get; set; }
public virtual ICollection<ExamDet> ExamDets { get; set; }
}
}
Exam
namespace AccessEsol.Models
{
using System;
using System.Collections.Generic;
public partial class Exam
{
public Exam()
{
this.Candidates = new HashSet<Candidate>();
this.ExamDets = new HashSet<ExamDet>();
}
public int ExamID { get; set; }
public string Name { get; set; }
public Nullable<System.DateTime> Date { get; set; }
public int AdminID { get; set; }
public string StartLevel { get; set; }
public virtual Administrator Administrator { get; set; }
public virtual ICollection<Candidate> Candidates { get; set; }
public virtual ICollection<ExamDet> ExamDets { get; set; }
}
}
There is also a model for Candidate that contains the CandID:
And the view model that uses these models:
namespace AccessEsol.Models
{
public class ExamQuestionsViewModel
{
public int QuID { get; set; }
public int CandID { get; set; }
public int ExamId { get; set; }
public string Text1 { get; set; }
public string Text2 { get; set; }
public string CorrectAnswer { get; set; }
public string Foil1 { get; set; }
public string Foil2 { get; set; }
public string Foil3 { get; set; }
public string Level { get; set; }
public string GrammarPoint { get; set; }
public virtual ICollection<ExamDet> ExamDets { get; set; }
}
}
This is the method that is to populate the view model:
public static List<ExamQuestionsViewModel> AddQuestions()
{
AccessEsolDataEntities db = new AccessEsolDataEntities();
string questionLevel = GetLevel();
int currentCand = GetCandID();
int currentExam = GetExamID();
//model = new DataAccess().Populate();
var qu = (from a in db.Questions
where a.Level_ == questionLevel
select a).ToList();
List<ExamQuestionsViewModel> exam = new List<ExamQuestionsViewModel>();
foreach (var IDs in exam)
{
currentCand = exam.CandID;
currentExam = exam.ExamId;
}
return (exam);
}
The error message I am getting is
'System.Collections.Generic.List<AccessEsol.Models.ExamQuestionsViewModel>'
does not contain a definition for 'ExamId' and no extension method
'ExamId' accepting a first argument of type
'System.Collections.Generic.List<AccessEsol.Models.ExamQuestionsViewModel>' could be found (are you missing a using directive or an assembly
reference?
What am I doing wrong here? All feedback much appreciated.
Please try this instead of your foreach:
foreach (var IDs in exam)
{
currentCand = IDs.CandID;
currentExam = IDs.ExamId;
}

How to Load Related Data in MVC with complex table structure

I have several classes which I will shorten for brevity. Below they are listed with the related properties/fields associated with this question.
public class AcademicYear
{
[Key]
public int AcademicYearId { get; set; }
}
public class Division
{
public Division()
{
this.CareerFields = new HashSet<CareerField>();
}
[Key]
public int DivisionId { get; set; }
// Foreign Keys
public int AcademicYearId { get; set; }
// Navigation Properites
public virtual AcademicYear AcademicYear { get; set; }
public virtual ICollection<CareerField> CareerFields { get; set; }
}
public class CareerField
{
public CareerField()
{
this.Clusters = new HashSet<Cluster>();
}
[Key]
public int CareerFieldId { get; set; }
// Foreign Keys
public int AcademicYearId { get; set; }
public int DivisionId { get; set; }
// Navigation Properties
public virtual AcademicYear AcademicYear { get; set; }
public virtual Division Division { get; set; }
public virtual ICollection<Cluster> Clusters { get; set; }
}
public class Cluster
{
public Cluster()
{
this.CareerFields = new HashSet<CareerField>();
}
[Key]
public int ClusterId { get; set; }
{
// Foreign Keys
public int AcademicYearId { get; set; }
// Navigation Properties
public virtual AcademicYear AcademicYear { get; set; }
public virtual ICollection<CareerField> CareerFields { get; set; }
}
}
public class Pathway
{
public Pathway()
{
this.CareerMajors = new HashSet<CareerMajor>();
}
[Key]
public int PathwayId { get; set; }
// Foreign Keys
public int AcademicYearId { get; set; }
public int ClusterId { get; set; }
// Navigation Properties
public virtual AcademicYear AcademicYear { get; set; }
public virtual Cluster Cluster { get; set; }
public virtual ICollection<CareerMajor> CareerMajors { get; set; }
}
public class CareerMajor
{
public CareerMajor()
{
this.Courses = new HashSet<Course>();
}
[Key]
public int CareerMajorId { get; set; }
public string FirstYearOffered { get; set; }
// Foreign Keys
public int AcademicYearId { get; set; }
public int PathwayId { get; set; }
// Navigation Properties
[HiddenInput(DisplayValue = false)]
public virtual AcademicYear AcademicYear { get; set; }
public virtual Pathway Pathway { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}
public class Course
{
public Course()
{
this.CareerMajors = new HashSet<CareerMajor>();
}
[Key]
public int CourseId { get; set; }
// Foreign Keys
public int AcademicYearId { get; set; }
public int? InstructorId { get; set; }
// Navigation Properties
public virtual ICollection<CareerMajor> CareerMajors { get; set; }
public virtual AcademicYear AcademicYear { get; set; }
}
I also have a ViewModel class to load all this for my controller
public class CMSIndex
{
public IEnumerable<Division> Divisions { get; set; }
public IEnumerable<CareerField> CareerFields { get; set; }
public IEnumerable<Cluster> Clusters { get; set; }
public IEnumerable<Pathway> Pathways { get; set; }
public IEnumerable<CareerMajor> CareerMajors { get; set; }
public IEnumerable<Course> Courses { get; set; }
}
I have a razor cshtml page (the auto CRUD defined Index page) where I start with the Division and I can load the related CareerFields. However, when I try to load Clusters, I get the error message
Server Error in '/' Application.
Value cannot be null.
Parameter name: source
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ArgumentNullException: Value cannot be null.
Parameter name: source
Here is my index method from the controller (note the commented out lines are what I have tried as well)
public ViewResult Index(Int32? divisionID, Int32? careerFieldID, Int32? clusterID, Int32? pathwayID, Int32? careerMajorID, Int32? courseID)
{
var viewModel = new CMSIndex();
viewModel.Divisions = db.Divisions
.Include(d => d.AcademicYear)
.Include(d => d.CareerFields)//
.Include(d => d.CareerFields.Select(cf => cf.Clusters))
//.Select(c => c.Clusters.Select(cl => cl.Pathways.Select(p => p.CareerMajors.Select(cm => cm.Courses)))))
.OrderBy(d => d.DivisionName);
if (divisionID != null)
{
ViewBag.DivisionID = divisionID.Value;
viewModel.CareerFields = viewModel.Divisions.Where(d => d.DivisionId == divisionID.Value).Single().CareerFields;
}
if (careerFieldID != null)
{
ViewBag.careerFieldID = careerFieldID.Value;
//viewModel.Clusters = viewModel.CareerFields.Where(cf => cf.CareerFieldId == careerFieldID.Value).Single().Clusters;
//viewModel.Clusters = viewModel.CareerFields.SelectMany(cf => cf.Clusters);
viewModel.Clusters = viewModel.CareerFields.Where(cf => cf.CareerFieldId == careerFieldID.Value).Single().Clusters;
}
return View(viewModel);
}
I am following the Contoso tutorial on loading related data. I seem to be able to load 1:m relationships, but I am unsure how to do this with m:m (e.g. CareerFields and Clusters).
And, I do have an initializer that has loaded data to pull and I am passing an ID (e.g. careerFieldID).
Where the exception is being thrown is on the line:
viewModel.Clusters = viewModel.CareerFields.Where(cf => cf.CareerFieldId == careerFieldID.Value).Single().Clusters;
And each commented variation.
Any help would be extremely appreciated.
Not saying that this is the issue, but have you checked the values are not null? In the line
viewModel.Clusters = viewModel.CareerFields
.Where(cf => cf.CareerFieldId == careerFieldID.Value).Single().Clusters;
is it possible that viewModel.CareerFields is null?
As some side notes:
With your null checks when you have nullables it's better to use their HasValue method e.g.
if (divisionID.HasValue)
{
...
}
The use of Single() can be a bit temperamental and can throw exceptions if no elements exist or if more than one exist. First() can be used to handle more than one (but this throws if none match), SingleOrDefault() will handle zero or one result and FirstOrDefault() will handle most things.
You can save a expression by putting your lambda in the single e.g.
viewModel.CareerFields = viewModel.Divisions
.Single(d => d.DivisionId == divisionID.Value).CareerFields;
Edit: I think the issue you are having is the same as in This Answer could you try changing your classes collections so the are initialised in the get when null. E.g for Division
public class Division
{
[Key]
public int DivisionId { get; set; }
// Foreign Keys
public int AcademicYearId { get; set; }
// Navigation Properites
public virtual AcademicYear AcademicYear { get; set; }
private ICollection<CareerField> careerFields;
public virtual ICollection<CareerField> CareerFields {
get { return careerFields ?? (careerFields = new HashSet<CareerField>()); }
set { careerFields = value; }
}
}
That's actually my preferred method anyway, this imposes it's own problem with your code as the fact that CareerFields was null means that for the given division, there are no associated CareerFields. This means that when your Single() call is hit it will throw the exception The source contains no elements as CareerFields will contain a empty hashset. This could be fixed by a change to SingleOrDefault().

Resources