Entity Framework one-to-one relationships errors on insert - mapping

I'm having some troubles getting a set of Entities setup to work correctly. I'm using EF v5 in VS2012 against SQL Server 2008 R2 Express.
Everything seems to be correct with the generated database but I'm not having any success writing to some of the tables.
I have a UserProfile object defined like:
[Table("UserProfile")]
public class UserProfile
{
[Key]
public long UserId { get; set; }
[StringLength(56)]
public string UserName { get; set; }
public Country Country { get; set; }
...
}
I also have the Country entity defined like:
[Table("Country")]
public class Country
{
[Key]
public int Id { get; set; }
[StringLength(2)]
public string CountryCode { get; set; }
[StringLength(100)]
public string CountryName { get; set; }
public ICollection<UserProfile> UserProfiles { get; set; }
...
}
The generated columns look correct in the database, if I script it out it looks good:
ALTER TABLE [dbo].[UserProfile] WITH CHECK ADD CONSTRAINT [UserProfile_Country] FOREIGN KEY([Country_Id])
REFERENCES [dbo].[Country] ([Id])
GO
Just for testing purposes in a controller action I have the following:
WebSecurity.CreateUserAndAccount(model.UserName, model.Password, new
{
Country = new Country { Id = 223, CountryCode = "UK", CountryName = "UK" },
...
});
When this WebSecurity method is executed I get the following error:
No mapping exists from object type MyApi.Data.Entities.Country to a known managed provider native type.
I tried setting up a configuration file to specify the relationship in code as well as the database but it's still not playing friendly.
The config looks like:
public class CountryEntityConfig : EntityTypeConfiguration<Country>
{
public CountryEntityConfig()
{
this.HasMany(x => x.UserProfiles)
.WithRequired()
.HasForeignKey(FKey => FKey.Country);
}
}
It feels really odd having a list of profiles in the country object am I getting some of the basics completely wrong with this? Any input appreciated.
EDIT:
I've revisted some classes and made a few changes, in the user profile I now have:
public int CountryId { get; set; }
public virtual Country Country { get; set; }
Country.cs
public class Country
{
public int CountryId { get; set; }
[StringLength(2)]
public string CountryCode { get; set; }
[StringLength(100)]
public string CountryName { get; set; }
public virtual ICollection<UserProfile> UserProfiles { get; set; }
}
And the database now contains two CountryId related fields in the UserProfile table with relationships to the Country table and I still get the original error message.
TIA,

The No mapping error is probably because you did not add the Country entity to the DbContext.
In the AccountModels.cs file, you will find a UsersContext that derives from DbContext, in there you must add a DbSet<Country>.
There are, however, other issues here. For instance, you are creating your Country table with a Key, and EF by default will give the Country table an autogenerated identity column. This means you can't insert a value for the ID, it will be auto generated.
Country is probably a lookup table anyways that you will populate with country values. So you would probably just set CountryId to the value of the country you want

Related

Multiple tables update MVC .net

I am new to MVC and this is my function. There are three tables (Order, OrderNotes, Notes), ID is their primary key. One Order can have many Notes, the table OrderNotes has foreign key OrderID(from Booking table) and NotesID(from Notes table). I want to have a Order Edit page to display individual Order (FirstName, LastName), also display a list of its Notes. Here is my DB structure:
Booking table:
{ID,
FirstName,
LastName
}
BookingNotes table:
{ID,
BookingID,
NotesID
}
Notes table:
{ID,
NoteName,
StatusID
}
So how can I implement the list of Notes since it's from multiple tables? It will be able to Create New Note, Delete existing Note in the list row record, not Edit. Linq used in DB query. Thanks.
It would be a better idea to have only 2 tables:
public class Book
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
// Navigational properties
public virtual List<Note> Notes { get; set; }
}
public class Note
{
public int ID { get; set; }
public int BookID { get; set; }
public string NoteName { get; set; }
public int StatusID { get; set; }
// Navigational properties
public virtual Book Book { get; set; }
public virtual Status Status { get; set; }
}
A third table is useful when you want to reuse the same Note for a different booking. However i think this is not the case.
So to retrieve data for your context make sure you have the DbSet<Book>
public class ApplicationDbContext : DbContext
{
public virtual DbSet<Book> Bookings { get; set; }
}
In your controller (or better in a repository class):
var BookingID = 10; // this is parameter passed to the function
var myBooking = this.dbContext.Bookings
.Include(p => p.Notes)
.ThenInclude(p => p.Status)
.FirstOrDefault(p => p.ID == BookingID);
Map the retrieved booking to a ViewModel, pass it to the View and you're good to go.

How to search and load data in database by using a string keyword

This is my ProgramCategories model
public class ProgramCategories
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
public string courseCategory { get; set; }
}
This is my course information model.
public class CourseCategory
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[Required(ErrorMessage = "Please Select Field of Study")]
[Display(Name = "Field of Study")]
public string courseField { get; set; }
[Required(ErrorMessage = "Please Select Course Name")]
[Display(Name = "Course Name", Prompt = "Course Name")]
public string courseName { get; set; }
[Display(Name = "Attachments")]
public virtual ICollection<File> Files { get; set; }
public virtual ICollection<FilePath> FilePaths { get; set; }
}
The courseCategory in ProgramCategories is equals to courseField in CourseCategory. whenever saving course information i can select the category of course via dropdown. The dropdown contains all the ProgramCategories. I loaded all the programCategories(Ex:BankCourse, science course, etc) into index View.
All these things are working for the moment.
What I want to know is when i click one programCategory i want to display all of the courses in that category. Ex: if i select science course i want to get all the science courses.
This is how I would approach it...
public ActionResult CourseByCategory(string crsCtgry)
{
return View(getCourseByCategory(crsCtgry));
}
private List<CourseCategory> getCourseByCategory(string crsCtgry)
{
return db.CourseCategory.Where(n => n.courseField == crsCtgry).Select(n => n).ToList();
}
What you're describing is a one-to-many relationship, so handle it as such. Create a true foreign key between the two tables and then you can automatically pull in the course that belong to a category via either eager or lazy loading in Entity Framework:
public class ProgramCategories
{
...
public virtual ICollection<CourseCategory> Courses { get; set; }
}
public class CourseCategory
{
...
[ForeignKey("Category")]
public int CategoryId { get; set; }
public virtual ProgramCategories Category { get; set; }
}
Here I've used the primary key of ProgramCategories as the foreign key. You don't technically have to do it that way. You could still use a string as you're doing with courseField; you would just need to define a max length for the property:
[ForeignKey("Category")]
[MaxLength(50)]
public string CourseField { get; set; }
Otherwise, the property will be represented as an NVARCHAR(MAX) in the database, which can't be indexed (it's essentially the same as TEXT). However, best practice is to key off the primary key.
Also, your class naming is horrendous. Classes should be singular ProgramCategory vs. ProgramCategories, and your CourseCategory name doesn't actually describe what this class is. Seems Course would be more appropriate, as it looks like that's what you're actually defining here, but maybe courseName is another should-be-a-foreign-key scenario. When you name your classes and properties on those classes, you should be thinking about how you would read it. For example, "The course category course name is 'Foo'." makes no sense, but "The course name is 'Foo'." makes perfect sense. That would translate to something like:
public class Course
{
public string Name { get; set; }
}

MVC4: Modelstate is not valid when creating a new record

I try to add a new Country which has a link to continent. When I press the "Create" button, it doesn't add a new record. I debugged my project and I think it's because the ValidState is false. The reason because of this is that the property "Continent" is null, but the Continent_Id isn't.
I have the same problem when I try to edit an existing Country. (I have populated my database with an SQL script in SQL Management Studio)
Can someone help me please?
Continent class:
public class Continent
{
public int Id { get; set; }
[Required, MaxLength(25)]
public string Name { get; set; }
//Navigation
public virtual List<Country> Countries { get; set; }
}
Country class
public class Country
{
public int Id { get; set; }
[Required, MaxLength(25)]
public string Name { get; set; }
[MaxLength(5)]
public string Abbreviation { get; set; }
public int Continent_Id { get; set; }
//Navigation
[Required, ForeignKey("Continent_Id")]
public virtual Continent Continent { get; set; }
}
Controller class ( create function )
//
// GET: /Countries/Create
public ActionResult Create()
{
ViewBag.Continent_Id = new SelectList(db.Continents, "Id", "Name");
return View();
}
//
// POST: /Countries/Create
[HttpPost]
public ActionResult Create(Country country)
{
var errors = ModelState.Values.SelectMany(v => v.Errors); //to check the errors
if (ModelState.IsValid)
{
db.Countries.Add(country);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.Continent_Id = new SelectList(db.Continents, "Id", "Name", country.Continent_Id);
return View(country);
Just before the line if (ModelState.IsValid) put this
ModelState.Remove("v_id");
Where v_id is your primarykey column name in your case
I fixed this issue by putting the Required validation off of Continent, and set it only at the Continent_Id. Now the ID property is required, but the Continent isn't.
public class Country
{
public int Id { get; set; }
[Required, MaxLength(25)]
public string Name { get; set; }
[MaxLength(5)]
public string Abbreviation { get; set; }
[Required] //added Required
public int Continent_Id { get; set; }
//Navigation
[ForeignKey("Continent_Id")] //removed Required
public virtual Continent Continent { get; set; }
}
Thanks for the responses !
I'm not sure, but I believe your issue is timing. Model validation happens automatically during binding; at that time, the Continent property is null. You set the property later but the model state is not re-evaluated when you check IsValid. I see three options:
Quick and dirty: Take the Required validation off of Continent and validate Continent_Id instead, adding a check in the controller to ensure a valid Continent is retrieved from Find().
Most work: Create a custom model binder to actually use the Continent_Id to retrieve and populate the Continent. You are almost there on this one since having both Continent_Id and Continent as properties of Country is redundant and an opportunity for inconsistencies.
Probably best option: Make your controller accept a view model that only has the data you expect to come back from the form and populate a Country object from it.
The reason the ModelState isn't valid is because you have marked the Continent property as required but in i guess in your view you don't have form fields the will bind to some properties of the Continent object.
So either don't mark the Continent object as required or provide a hidden field with a name of Continent.Id or Continent.Name so that the model binder will populate the Continent property:
#Html.HiddenFor(m => m.Continent.Id)
But that will lead to the next problem: You habe marked the Name property of the Continent class as required so you will have to provide a form field for that property too.
The base problem is, that you try to reuse your repository classes as viewmodel classes.
A better approach would be to use separate classes as viewmodels to pass your data between the controller and the view:
class CountryViewModel {
public int Id { get; set; }
[Required, MaxLength(25)]
public string Name { get; set; }
[MaxLength(5)]
public string Abbreviation { get; set; }
public int Continent_Id { get; set; }
}
To map between your Country and CountryViewModel object use a mapper like AutoMapper.

EntityType 'Category' has no key defined. Define the key for this EntityType [duplicate]

This question already has answers here:
EntityType has no key defined error
(13 answers)
Closed 6 years ago.
Developing a basic ASP.net MVC 4 application. Its a simple product catalog application, where in I have 2 database tables ('Category' and 'Products')
There is a foreign key reference of 'Category id' (primary key in Category table) in 'Products' table.
When I run the application, I am getting error message (listed below).
System.Data.Entity.Edm.EdmEntityType: : EntityType 'Category' has no key defined. Define the key for this EntityType.
System.Data.Entity.Edm.EdmEntitySet: EntityType: EntitySet 'Category' is based on type 'Category' that has no keys defined
This looks like a common error for newbies,I did check all the related solutions to 'Entity key '' has no key defined.' but still my problem is not solved, Kindly help me in understanding this problem and what is the correct solution to this problem.
Below are my model classes
Category.cs
namespace ChemicalStore.Models
{
public partial class Category
{
public int CatId { get; set; }
public string CatName { get; set; }
public string CatDescription { get; set; }
public List<Product> Product { get; set; }
}
}
Products.cs
namespace ChemicalStore.Models
{
public class Product
{
public int ProductId { get; set; }
public int CatId { get; set; }
public string ProductTitle { get; set; }
public string ProductPrice { get; set; }
public string ProductDescription { get; set; }
public string ProductPackage { get; set; }
}
}
You should add attribute [Key] before property CatId:
using System.ComponentModel.DataAnnotations;
public partial class Category
{
[Key]
public int CatId { get; set; }
public string CatName { get; set; }
public string CatDescription { get; set; }
public List<Product> Product { get; set; }
}
The problem is that EF can work only when it knows primary key of table. By default EF recognize as primary key property with name Id. If your table has another primary key, you can mark it with attribute [Key] or set Key with fluent configuration.
Entity Framework uses a primary key field to create the primary key column on the generated table.
It uses convention to get this column with some variations:
If the field is called id or any casing variance;
If the field is called ClassNameId of any casing variance;
I may be missing some more conventions, but these are the most common cases.
If you don't have any field with this conventions you need to mark your desired primary key with the attribute [Key]:
[Key]
public int CatId { get; set; }
I was able to solve this by adding a setter to my key property; I only had a getter before.
public int Id { get; set; }
Just place [key] attribute on above id ..
[Table("employee")]
public class Employee
{
[Key]
public int Empno { set; get; }
public string Empname { set; get; }
}
Entity classes are auto generated..
Manual changes to those files will be overwritten if the code is regenerated.
You need to create a partial class with all your metadata
[MetadataType(typeof(Category.CategoryMetadata))]
public partial class Category
{
internal sealed class CategoryMetadata
{
[Key]
public int CatId { get; set; }
[Required]
public string CatName { get; set; }
public string CatDescription { get; set; }
public List<Product> Product { get; set; }
}
}
Read more on MSDN
Hi if you are getting below error.
""One or more validation errors were detected during model generation:
Checking.Models.Employee: : EntityType 'Employee' has no key defined. Define the key for this EntityType.""
just check your table column name and defined property name same or not .
if not then correct it proble resolved.
In my case I fixed this problem adding the right connectionString in the web.config/app.config file.
I had forgotten adding it and the DBContext was not able to communicate with the DB.
Hope it helps

MVC 3 database create/insert error

I'm getting the error
The member with identity
'UsersModel_Group' does not exist in
the metadata collection. Parameter
name: identity.
when calling the db.UsersModel.Add(SomeModel) method. I checked the controllers and models if there's any problem with namespaces but there's nothing weird that I found. I did change some classes name but there are no errors upon build. Any suggestions?
here are the classes that might be relevant:
public class UsersModel{
public int ID {get; set;}
...
[ForeignKey("GroupID")]
[Display(Name = "Group")]
public virtual GroupModel Group { get; set; }
[Required]
public virtual int GroupID { get; set; }
public virtual List<GroupModel> GroupList { get; set; }
}
public class GroupModel {
public int ID { get; set;}
...
[Required]
public int ID { get; set; }
[Required]
[StringLength(20,ErrorMessage = "The {0} must not exceed {2} characters")]
public string Name { get; set; }
}
If you've changed your model after the database was created you will need to recreate the database. EF Code First stores details of your model inside a metadata table. If this metadata does not match that of your model then you will get an error.
If you don't want to drop your database you can delete the metadata table and then manually make your database changes so that it matches your model.

Resources