How to Add related entites to database using EntityFramework - c#

I am trying add the cart to database but don't know how to add related Entities
My related tables are ( carts , products , productoptions , options)
How Can I add or Update those tables at the same time? And how can I set Foreign keys to related Tables
thanks...

You will create models for each of your tables (see below)
Then if you add just a child you will have to add it with the foreig nkey property populated
var test = childObj { parentPropertyId = parentPropertyIdValue}
If you add parent and child together you can just add and entity mework will take care of that. For example:
var test = new parentObj {
someProperty = someValue,
childProperty = new childObj{
//here will not have to populate the parentPropertyId
}
}
See sample models for your above tables
Use the [Key] attribute to specify your primary key
Use the [ForeignKey] attribute above your related entity property to specify which property to use as foreign key
Use an ICollection to access the children of an object
public class Carts
{
[Key]
public int Id { get; set; }
public int Userid { get; set; }
public DateTime CreatedDate { get; set; }
public ICollection<Products> Products { get; set; }
}
public class Products
{
[Key]
public int Id { get; set; }
public string SerialNumber { get; set; }
public string StockCode { get; set; }
public int CartId { get; set; }
public int Quantity { get; set; }
[ForeignKey(nameof(CartId))]
public Carts Cart { get; set; }
}
public class ProductOptions
{
[Key]
public int Id { get; set; }
public int ProductId { get; set; }
public int OptionId { get; set; }
[ForeignKey(nameof(ProductId))]
public Products Products { get; set; }
[ForeignKey(nameof(OptionId))]
public Options Options { get; set; }
}
public class Options
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int Quantity { get; set; }
public int ParentId { get; set; }
public int GrandParentId { get; set; }
}

Related

Require One of Multiple Foreign Keys in Entity Framework

I'm basically trying to enforce this in Entity Framework: Require Only One Of Multiple Columns Be Not Null
My database has several 1:m relationships where the child entity belongs to one of several parent entities. For example, let's say I have tables for Teachers, Students, and Guardians. Each of those can have many PhoneNumbers and EmailAddresses. I am using EF Code First, and my models look something like:
public class Teacher {
public int Id { get; set; }
public string Name { get; set; }
public List<PhoneNumber> PhoneNumbers { get; set; }
public List<EmailAddress> EmailAddresses { get; set; }
}
public class Student {
public int Id { get; set; }
public string Name { get; set; }
public List<PhoneNumber> PhoneNumbers { get; set; }
public List<EmailAddress> EmailAddresses { get; set; }
}
public class Guardian {
public int Id { get; set; }
public string Name { get; set; }
public List<PhoneNumber> PhoneNumbers { get; set; }
public List<EmailAddress> EmailAddresses { get; set; }
}
public class PhoneNumber {
public int Id { get; set; }
public string Number { get; set; }
}
public class EmailAddress {
public int Id { get; set; }
public string Email { get; set; }
}
When I run the migration, this creates the database with the tables/columns I would expect. The PhoneNumbers and EmailAddresses tables each have columns Teacher_Id, Student_Id, and Guardian_Id, which are foreign keys to their respective parent entity. However, there are no constraints on how many parent entities can be set on the child. For example, I can create a PhoneNumber that has all three parent IDs set to null, or I can set both a Teacher_Id and a Guardian_Id.
I tried adding a required attribute to the parents like so:
public class Teacher { // Also Student/Guardian
public int Id { get; set; }
public string Name { get; set; }
[Required]
public List<PhoneNumber> PhoneNumbers { get; set; }
[Required]
public List<EmailAddress> EmailAddresses { get; set; }
}
That does not seem to have any effect.
I think there is no way to do this on entities. Instead, create a migration and try to alter the table in migration class like this:
public partial class YourMigrationName: Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("ALTER TABLE [dbo].[PhoneNumber]
WITH CHECK ADD CONSTRAINT [CK_PhoneNumer_Teacher_Student_Guardian] CHECK (Teacher_Id
is not null or Student_Id is not null or Guardian_Id is not null)
GO
ALTER TABLE [dbo].[EmailAddress] WITH CHECK ADD CONSTRAINT
[CK_EmailAddress_Teacher_Student_Guardian] CHECK (Teacher_Id is not null or
Student_Id is not null or Guardian_Id is not null)
");
}
}
Try this:
public class PhoneNumber
{
public int Id { get; set; }
public string Number { get; set; }
//Added this code:
[Required]
public Teacher Teacher { get; set;}
}
public class EmailAddress {
public int Id { get; set; }
public string Email { get; set; }
//Added this code:
[Required]
public Teacher Teacher { get; set;}
}
That would make sure you cannot create PhoneNumber without Teacher. You can also do this:
public class PhoneNumber
{
public int Id { get; set; }
public string Number { get; set; }
public int TeacherId
public Teacher Teacher { get; set;}
}
That would also detect that you want to add constraint on your PhoneNumber. Both ways work fine.

how to update the model class recipe?

I have two model classes Category and Recipe and their relationship in one to many. I want to Edit the Recipe and also change the category that the recipe belongs to.Thanks in advance.
public class CookContext : DbContext
{
public CookContext(): base("cookContext")
{
}
public DbSet<Recipe> Recipes { get; set; }
public DbSet<Category> Categories { get; set; }
}
public class Category
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Recipe> Recipes { get; set; }
}
public class Recipe
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Description { get; set; }
[Required]
public string Ingridients { get; set; }
public string Image { get; set; }
public Category category { get; set; }
}
[HttpPost]
[ValidateInput(false)]
public ActionResult EditRecipe(Recipe recipe, int? categoryName)
{
var category = context.Categories.Where(c => c.Id ==
(int)categoryName).FirstOrDefault();
context.Entry(recipe).State = EntityState.Modified;
recipe.category = category;
context.SaveChanges();
}
The error messages i get are:
1.
[DbUpdateException: An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types.
2.
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.
Try by adding the field CategoryId to your Recipe class, also, the category property should begin with a capital "C".
The collection property should be marked virtual if you want the data to be lazy loaded (only loaded when needed) otherwise, you may load all recipes for a given category every time you make a query:
public class Recipe
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Description { get; set; }
[Required]
public string Ingridients { get; set; }
public string Image { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
public class Category
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Recipe> Recipes { get; set; }
}
If it doesn't work try by setting up the ForeignKey attribute:
public class Recipe
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Description { get; set; }
[Required]
public string Ingredients { get; set; }
public string Image { get; set; }
[ForeignKey("Category")]
public int CategoryId { get; set; }
public Category Category { get; set; }
}
public class Category
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Recipe> Recipes { get; set; }
}

Getting DbUpdateException when adding a row

I'm trying to add a record in a table, but it's not working. The error message tells me that I cannot insert an explicit value in identity column for ProductCategories, but I don't know that I'm doing that. Maybe there is something I'm not getting about entity navigation, or my models are somehow not correctly linked?
SqlException: Cannot insert explicit value for identity column in table 'ProductCategories' when IDENTITY_INSERT is set to OFF.
Cannot insert explicit value for identity column in table 'Products' when IDENTITY_INSERT is set to OFF.
System.Data.SqlClient.SqlCommand+<>c.b__108_0(Task result)
DbUpdateException: An error occurred while updating the entries. See the inner exception for details.
Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch+d__32.MoveNext()
This is the code that fails (at await _context.SaveChangesAsync();):
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> FrontPageProduct(ViewModelFrontPageProduct frontPageProduct)
{
var fpp = new FrontPageProduct()
{
ProductCategoryId = frontPageProduct.ProductCategoryId,
ProductId = frontPageProduct.ProductId,
SortOrder = 0
};
_context.Add(fpp);
await _context.SaveChangesAsync();
return View("Index", new { id = fpp.ProductCategoryId, tab = 2 });
}
These are the involved entity models:
public class Product
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Title { get; set; }
public string Info { get; set; }
public decimal Price { get; set; }
public List<FrontPageProduct> InFrontPages { get; set; }
public List<ProductInCategory> InCategories { get; set; }
}
public class ProductCategory
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int SortOrder { get; set; }
public string Title { get; set; }
[ForeignKey(nameof(ParentCategory))]
public int? ParentId { get; set; }
public ProductCategory ParentCategory { get; set; }
public ICollection<ProductCategory> Children { get; set; } = new List<ProductCategory>();
public List<ProductInCategory> ProductInCategory { get; set; }
}
public class FrontPageProduct
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int ProductCategoryId { get; set; }
public int ProductId { get; set; }
public int SortOrder { get; set; }
[ForeignKey("ProductId")]
public virtual Product Product { get; set; }
[ForeignKey("ProductCategoryId")]
public virtual ProductCategory ProductCategory { get; set; }
}
The debug inspection of the fpp-object shows that the values for ProductCategoryId and ProductId are correct:
Where is/are my mistake/s?
EDIT I added the suggested [Key] and [DatabaseGenerated(DatabaseGeneratedOption.Identity)] to all the models, but I still get the same error.
I think that the Id field is always set to be primary key as default in EF anyway.
EDIT 2 I tried adding [FromBody] in my controller method, but that only resulted in a blank screen, no error message, and no changes being made to the database.
EDIT 3 I added [ForeignKey("ProductId")] and [ForeignKey("ProductCategoryId")] to the FrontPageProduct model, but still get the same SqlException.
EDIT 4 These are the foreign keys of my four tables:
FrontPageProducts:
FK_FrontPageProducts_ProductCategories_ProductCategoryId
FK_FrontPageProducts_Products_ProductId
ProductCategories:
FK_ProductCategories_ProductCategories_ParentId
Products:
none
ProductsInCategories:
FK_ProductsInCategories_FrontPageProducts_FrontPageProductId
FK_ProductsInCategories_ProductCategories_ProductCategoryId
FK_ProductsInCategories_Products_ProductId
Looks like you don't need to set DatabaseGenerated attribute for "int Id" fields, it is a convention and assumed that it is Identity Column.
Btw, are you sure you are getting the same error? The imgur link does not work for me. Do you really need Product and ProductCategory on your FrontPage class, if you can easily comment them out and test, please do so, if not you can try setting the values for them like below.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> FrontPageProduct(ViewModelFrontPageProduct frontPageProduct)
{
var fpp = new FrontPageProduct()
{
ProductCategoryId = frontPageProduct.ProductCategoryId,
ProductId = frontPageProduct.ProductId,
Product = _context.Set<Product>().Find(frontPageProduct.ProductId),
ProductCategory = _context.Set<ProductCategory>().Find(frontPageProduct.ProductCategoryId),
SortOrder = 0
};
_context.Add(fpp);
await _context.SaveChangesAsync();
return View("Index", new { id = fpp.ProductCategoryId, tab = 2 });
}
Apply Key and DatabaseGenerated attributes to every Id column on your models, so EF knows that it is an identity column and it needs to get back the generated id value.
public class Product
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Title { get; set; }
public string Info { get; set; }
public decimal Price { get; set; }
[InverseProperty("Product")]
public IEnumerable<FrontPageProduct> InFrontPages { get; set; }
public List<ProductInCategory> InCategories { get; set; }
}
public class ProductCategory
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int SortOrder { get; set; }
public string Title { get; set; }
[ForeignKey(nameof(ParentCategory))]
public int? ParentId { get; set; }
public ProductCategory ParentCategory { get; set; }
public ICollection<ProductCategory> Children { get; set; } = new List<ProductCategory>();
public List<ProductInCategory> ProductInCategory { get; set; }
}
public class FrontPageProduct
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int ProductCategoryId { get; set; }
public int ProductId { get; set; }
public int SortOrder { get; set; }
[ForeignKey("ProductId")]
public virtual Product Product { get; set; }
[ForeignKey("ProductCategoryId ")]
public virtual ProductCategory ProductCategory { get; set; }
}
Edit: you should add navigation properties, just like I added above. Making them virtual also helps with lazy loading.
The Id field should be the primary key in the database so you can specify that in the entity models. - Add the [Key]
public class Product
{
[Key]
public int Id { get; set; }
public string Title { get; set; }
public string Info { get; set; }
public decimal Price { get; set; }
public IEnumerable<FrontPageProduct> InFrontPages { get; set; }
public List<ProductInCategory> InCategories { get; set; }
}

Mapping self-referencing table data into another model (no automapper is used)

I have this table using Entity Framework code first approach :
public class WebsitePart
{
public WebsitePart()
{
SubParts = new HashSet<WebsitePart>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public Nullable<int> ParentId { get; set; }
[StringLength(100)]
[Index("UQ_WebsitePart_Key", IsUnique = true)]
public string Key { get; set; }
public virtual WebsitePart Parent { get; set; }
public virtual ICollection<WebsitePart> SubParts { get; set; }
}
I need after getting the list of WebsiteParts to map it into List of another model where each element of this list has ParentId=null and down to the end of its grandsons(traversing) .
This the model I want to map to:
public class WebPartViewDto
{
public int Id { get; set; }
public string Key { get; set; }
public IList<WebPartViewDto> SubWebParts { get; set; }
}
Could you please show me how to map it with performance is taken into account?

Save complexa data using entity framework

Hi every one I want to save complex data using Entity Framework and C#. I have 2 classes Product and Order defined as follows
Product Class
public class Product
{
[Key]
public int Id { get; set; }
public string SKU_Code { get; set; }
public string Product_Name { get; set; }
public string Quantity { get; set; }
public string Price { get; set; }
public string Image { get; set; }
public DateTime Created_Date { get; set; }
public DateTime Modified_Date { get; set; }
}
Order Class
public class Order
{
[Key]
public long ID { get; set; }
public string Order_Id { get; set; }
public string Payment_Type { get; set; }
public string Customer_Name { get; set; }
public string Shipping_Address { get; set; }
public DateTime Order_Date { get; set; }
public DateTime Modified_Date { get; set; }
public bool Flag { get; set; }
public List<Product> ProductDetails { get; set; }
}
And I want to save data Order details and my piece of code is as follows.
public Order Add(Order odrerDetails)
{
using (var context = new EcommerceDBContext())
{
var MyOrder_Id = Helper.Random(7); //Generate random orderID from my class
foreach (var detail in odrerDetails.ProductDetails)
{
odrerDetails.Order_Id = MyOrder_Id;
odrerDetails.Quantity = Convert.ToInt32(detail.Quantity);
odrerDetails.Amount = Convert.ToDouble(detail.Price);
//Other Details
context.objOrderListing.Add(odrerDetails);
}
context.SaveChanges();
return odrerDetails;
}
}
This gives me perfect data but when it comes to context.SaveChanges(); it return's me error.
An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types.
To me you domain model seems all wrong. The order should just be used for grouping, its a typical e-commerce scenario.
When you get a receipt of your purchases, you get one receipt with every Item and price listed next to it. Its considered as one order of multiple things, not multiple orders of multiple things.
Reading your last comment, you cant have multiple orders with the same order id. Try to understand the domain first before trying to solve it with code. Also,you have no notion of a Customer with an Order.
public class Product
{
[Key]
public int Id { get; set; }
public string SKU_Code { get; set; }
public string Product_Name { get; set; }
public string Price { get; set; }
public string Image { get; set; }
public DateTime Created_Date { get; set; }
public DateTime Modified_Date { get; set; }
}
public class Order
{
[Key]
public long ID { get; set; }
public string Order_Id { get; set; }
public string Payment_Type { get; set; }
public string Customer_Name { get; set; }
public string Shipping_Address { get; set; }
public DateTime Order_Date { get; set; }
public DateTime Modified_Date { get; set; }
public bool Flag { get; set; }
public List<OrderLineItem> Items { get; set; }
}
public class OrderLineItem
{
[Key]
public long ID { get; set; }
public long Order_Id { get; set; }
public long Product_Id {get; set;}
public int Quantity {get; set;}
}

Categories

Resources