I am new to entity framework, I was trying to implement a simple shopping cart using code first approach, and I didnt understand why entity generates the table in strange way below. Here is the cut down version of my classes:
Product.cs
public class Product
{
[Key]
public int ID { get; set; }
public int ProductCategoryID { get; set; }
public string ProductNumber { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Specification { get; set; }
public string Color { get; set; }
public string Capacity { get; set; }
public string CapacityUnitMeasureCode { get; set; }
public decimal Price { get; set; }
public decimal Cost { get; set; }
public int Stock { get; set; }
}
ShoppingCart.cs
public class ShoppingCart
{
[Key]
[Column (Order=1)]
public int ID { get; set; }
[Key]
[Column(Order = 2)]
public int ProductID { get; set; }
public int Quantity { get; set; }
public DateTime CreatedDate { get; set; }
public virtual List<Product> products { get; set; }
}
Because of this line
public virtual List products { get; set; }
Entity generates the Product table with 2 additional foreign keys:
ShoppingCart_ID & ShoppingCart_ProductID
Which I dont understand. my intention was to create a List of product that associated to a particular shopping cart. What I am I doing wrong. Could someone shed some light please!
SInce you have ProductID as one of the property in shopping cart class and you have virtual product collection in shopping cart, EF has established relationship between shopping cart and product class.
as suggested in comment you can remove product id class or you can create a view model class and establish relation ship between shopping cart and product class.
Sample View model can be
public class ShoppingCartProduct
{
[Key]
[Column (Order=1)]
public int ID { get; set; }
[Key]
[Column(Order = 2)]
public int ProductID { get; set; }
}
you can read about view model here
http://www.google.co.in/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CB4QFjAA&url=http%3A%2F%2Frachelappel.com%2Fuse-viewmodels-to-manage-data-amp-organize-code-in-asp.net-mvc-applications&ei=EP20VNqDHcTkuQTqvYGoAw&usg=AFQjCNHdOjOFhZGuBiLHZJ0wBGsG9qQtXw&sig2=rSFNWzWstWP0z0yRDhuXXQ
The great solution for you is to make a class ShopingCart wich contain all your products and their number:
[Table("Cart")]
public class ShopingCart
{
[Key]
public int Id { get; set; }
public DateTime CreatedDate { get; set; }
public virtual ICollection<ItemCart> Products { get; set; } // relationship one-to-many
}
And the class wich contains your ItemCart
[Table("ItemCart")]
public class ItemCart
{
[Key]
public int Id { get; set; }
public int Quantity { get; set; }
public virtual Product Product { get; set; } // relationship one-to-one
}
If you want to learn more look on this page: entity-tutorial
And try to make think simple: You have just 3 possible relationships:
one-to-one
one-to-many
many-to-many but here is creating an intermittent table link
Hope to be useful for you!
Related
So my use case is pretty simple, I have a vehicle and accessories for the vehicle. Now I have created 3 tables, one for the vehicle, one for the accessory and a many to many table as below:
public class Vehicle
Vehicle table
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
public string RegistrationNumber { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public int Year { get; set; }
public int Kilometers { get; set; }
public string VehicleIdentificationNumber { get; set; }
public decimal RetailPrice { get; set; }
public decimal CostPrice { get; set; }
public ICollection<VehicleAccessory> VehicleAccessories { get; set; }
public ICollection<VehicleImage> VehicleImages { get; set; }
public DateTime DTCreated { get; set; }
public DateTime DTUpdated { get; set; }
}
Accessory table
public class Accessory
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
public string Description { get; set; }
public ICollection<VehicleAccessory> VehicleAccessories { get; set; }
}
Linking table
public class VehicleAccessory
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
public long VehicleId { get; set; }
public Vehicle Vehicle { get; set; }
public long AccessoryId { get; set; }
public Accessory Accessory { get; set; }
}
Now I manually added an entry to the db to link the accessory and the vehicle table but it doesn't get recognized if I query the vehicle table to get the VehicleAccessories property, it just returns null. I tried to use include on the property but it gave me a circular reference error. On a side note, I have no idea how to add, using EF, into a many to many table.
To try and get the records I am using:
_context.Vehicles.ToList();
Can someone possibly shed some light to why this isn't working.
1) Did you create relationship between these tables in SQL Server?
2) Did you use scaffold-dbcontext command in nuget package console? your VehicleAccessory table looks like that you didn't use scaffold-dbcontext command.
3) Use code below
_context.Vehicles.Include(x => x.VehicleAccessories).Include("VehicleAccessories.Accessory").ToList();
I am new to use ASP.net and MVC and in need of some help.I am currently working on a project which is an online recipe book, and I have various tables but the two tables I want to combine into one view is Recipe and RecipeIngredients, as shown below:
Recipe.cs
namespace TheOnlineFoodBook.Models
{
public class Recipe
{
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int RecipeID { get; set; }
[Display(Name = "Recipe")]
public string RecipeName { get; set; }
[Display(Name= "Cuisine")]
public int CuisineID { get; set; }
public string Directions { get; set; }
[Display(Name = "Preperation Time:")]
public double PreperationTime { get; set; }
[Display(Name = "Cooking Time:")]
public double CookingTime { get; set; }
public virtual List<RecipeIngredient> RecipeIngredients { get; set; }
[ForeignKey("CuisineID")]
public virtual Cuisine Cuisine { get; set; }
}
}
RecipeIngredient.cs
public class RecipeIngredient
{
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public int RecipeID { get; set; }
public int IngredientID { get; set; }
public double Quantity { get; set; }
public int MeasurementID { get; set; }
public string Notes { get; set; }
public virtual Recipe Recipe { get; set; }
public virtual Measurement Measurement { get; set; }
public virtual Ingredient Ingredient { get; set; }
}
}
I've read a little about combining models to create a viewModel but i'm not sure how I would go about doing this, and I also want to be able to add multiple RecipeIngredients entries at the same time when creating a Recipe. Currently I have the basic CRUD views working which entity framework created for me.
You already have a "Recipe" object in "RecipeIngredient" so using "RecipeIngredient" as model in your view would give you access to "Recipe" properties, another approach you could take is using #modelTuple<Recipe,RecipeIngredient> in your view after passing new Tuple<Person, Order>(new Recipe(),new RecipeIngredient()); as you would pass a model, but I wouldn't see the use in following the later one since "RecipeIngredient" already has "Recipe"
Will this do what you need?
public class RecipeViewModel
{
public Recipe Recipe { get; set; }
public List<RecipeIngredients> RecipeIngredientsList { get; set; }
}
You won't be able to use data annotations as effectively, but if that isn't a concern you will now be able to attach multiple RecipeIngredients to the same Recipe for your page.
I am doing a code first example, and basically I have Products and Categories.
The Category Model is as follows :
public class Category
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
}
and the Product model is as follows:
public class Product
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Description { get; set; }
[Required]
public decimal Price { get; set; }
[Required]
public int Stock { get; set; }
public string ImageName { get; set; }
//Category Navigation
public int CategoryId { get; set; }
public Category Category { get; set; }
}
When I try to create a Controller with the Web API 2 Controller with actions, using Entity Framework scaffold, I am getting an error :
There was an error running the selected code generator : 'Key already
exists in table'
I am suspecting its the Category Navigation part of the Product Model since without that code, the scaffold works.
What am I doing wrong? I tried to create it as a virtual property but I am still getting the same error.
You need to add the Model classes in your DbContext
public DbSet<Product> Products{ get; set; }
public DbSet<Category> Categories{ get; set; }
Now you could do the scaffolding.
This question will also help for a better understanding
I'm trying to create a controller with scaffolding based on the following model (with no previously created context, but I chose the option to create it alongside the controller):
namespace MvcMusicStorePractice.Models
{
public class Album
{
public virtual int AlbumId { get; set; }
public virtual int GenreId { get; set; }
public virtual int ArtistId { get; set; }
public virtual string Title { get; set; }
public virtual decimal Price { get; set; }
public virtual string AlbumArtUrl { get; set; }
public virtual Genre Genre { get; set; }
public virtual Artist Artist { get; set; }
}
}
But I keep getting the following error:
Album::EntityType 'Album' has no key defined. Define the key for this EntityType.
I'v tried the following solutions:
Adding the [Key] attribute to the AlbumId;
Changing the public virtual int AlbumId to simply public int Id.
It still does not work however. Does anyone know what the problem is?
In order to use the entity framework, every entity needs a key. This is how EF tracks objects in its cache, posts updates back to the underlying data store, and links related objects together:
namespace MvcMusicStorePractice.Models
{
public class Album
{
[Key]
public int AlbumId { get; set; }
public int GenreId { get; set; }
public int ArtistId { get; set; }
public string Title { get; set; }
public decimal Price { get; set; }
public string AlbumArtUrl { get; set; }
public virtual Genre Genre { get; set; }
public virtual Artist Artist { get; set; }
}
}
Mind the [key] annotation that will make that field the PK.
Also make sure to only use "Virtual" with foreign objects (Only Genre & Artist)/
I have tried different models and configurations without progress. Have search for this specific usage but no success, found close but not same.
I have a product that is related to other products, so far so good if only one relation, e.g. "Related products"
The problem comes when adding additional relations e.g. "Similar".
What I am after is a self-referencing named relation, ideally a three column foreign key table; ProductId, RelatedProductId, RelationId
A product can have multiple named relations and a relation has one or more products (the related ones). I would like to avoid defining the name of the relation multiple times.
One idea has been as follows:
public class Product
{
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<Relation> Relations { get; set; }
}
public class Relation
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
Another idea has been using a special table:
public class Product
{
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<ProductRelation> Relations { get; set; }
}
public class Relation
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ProductRelation> Products { get; set; }
}
public class ProductRelation
{
[Key, Column(Order = 0)]
public virtual int ProductId { get; set; }
[Key, Column(Order = 1)]
public virtual int RelatedProductId { get; set; }
[Key, Column(Order = 2)]
public virtual int RelationId { get; set; }
[ForeignKey("ProductId")]
public virtual Product Product { get; set; }
[ForeignKey("RelatedProductId")]
public virtual Product RelatedProduct { get; set; }
[ForeignKey("RelationId")]
public virtual Relation Relation { get; set; }
}
The above example is the wanted result layout, how I wish to access it when retrieved, most likely need to be created in that way.
The below seems to be more clean from a db perspective with a three column mapping table
My questions are:
What is the recommended approach and why?
How to set up the mapping with keys properly so the database understand the relations as far as possible?