How do I save data in related tables? - c#

I have a question. I created a table with many to many relationships as below. What code should I write so that I can enter multiple categories when adding a product to the database?
I would be glad if you explain with an example.
For example, I can enter product.name information with the name information I received from the user, but I do not know how to save data in the relevant tables.
public class Category
{
public int CategoryId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public List<ProductCategory> ProductCategories { get; set; }
}
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public double? Price { get; set; }
public string Description { get; set; }
public string ImageUrl { get; set; }
public bool IsApproved { get; set; }
public bool IsHome { get; set; }
public List<ProductCategory> ProductCategories { get; set; }
}
public class ProductCategory
{
public int CategoryId { get; set; }
public Category Category { get; set; }
public int ProductId { get; set; }
public Product Product { get; set; }
}

You can insert them by the join table like this:
var product = new Product { Name = "AA" };
var categories = new List<Category>
{
new Category{ Name = "a"},
new Category{ Name = "b"},
new Category{ Name = "c"},
};
foreach (var category in categories)
{
_context.ProductCategory.Add(
new ProductCategory
{
Product = product,
Category = category
});
}
_context.SaveChanges();

I am not sure which version you are using. with EF Core 5.o find an example at https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-5.0/whatsnew
Models:
public class Category
{
public int CategoryId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public ICollection<Product> Products { get; set; }
}
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public double? Price { get; set; }
public string Description { get; set; }
public string ImageUrl { get; set; }
public bool IsApproved { get; set; }
public bool IsHome { get; set; }
public ICollection<Category> Categories { get; set; }
}
Or If you are using EE 6 or EF Core 3.1 then your models should be like:
public class Category
{
public int CategoryId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public ICollection<Product> Products { get; set; }
public ProductCategory ProductCategorie { get; set; }
}
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public double? Price { get; set; }
public string Description { get; set; }
public string ImageUrl { get; set; }
public bool IsApproved { get; set; }
public bool IsHome { get; set; }
public ICollection<Category> Categories { get; set; }
public ProductCategory ProductCategorie { get; set; }
}
public class ProductCategory
{
public int CategoryId { get; set; }
public Category Category { get; set; }
public int ProductId { get; set; }
public Product Product { get; set; }
}
For inserting data to Many-Many tables: https://learn.microsoft.com/en-us/aspnet/core/data/ef-mvc/complex-data-model?view=aspnetcore-5.0
then please look at the section:Seed database with test data

Related

How do I show CategoryName (subcategory) directly instead of Category (parent)?

I have a list of products.
var products = await unitOfWork.ProductRepository.GetAllWithDetailsAsync();
This is the model, so far so good.
public class ProductModel
{
public int Id { get; set; }
public int ProductCategoryId { get; set; }
public string CategoryName { get; set; }
public string ProductName { get; set; }
public decimal Price { get; set; }
public ICollection<int> ReceiptDetailIds { get; set; }
}
I also have ProductCategoryModel.
public class ProductCategoryModel
{
public int Id { get; set; }
public string CategoryName { get; set; }
public ICollection<int> ProductIds { get; set; }
}
The problem is with the returned Category name. Instead of returning the correct data, it returns Data.Entities.Product.
In debug mode, after expanding product, I can expand Category and inside it is CategoryName - the expected string.
How do I show CategoryName directly instead of Category?
While requesting Products in your UnitOfWork include Category .Include("Category")
public class ProductModel
{
public int Id { get; set; }
public int ProductCategoryId { get; set; }
public string ProductName { get; set; }
public decimal Price { get; set; }
public ICollection<int> ReceiptDetailIds { get; set; }
public ProductCategoryModel Category { get; set; }
public string CategoryName => Category.CategoryName;
}
https://learn.microsoft.com/en-us/ef/ef6/querying/related-data

Entity Framework creates a new record per foreign key in another table while seeding

I'm trying to seed a database using EF.
I have a table that holds products (phones) and a Category table that differentiates between different types of products.
public class Category
{
public int CategoryId { get; set; }
public string Name { get; set; }
public DateTimeOffset? CreationDate { get; set; }
public DateTimeOffset? UpdateDate { get; set; }
public virtual List<IProduct> Products{ get; set; }
public Category()
{
this.CreationDate = DateTimeOffset.UtcNow;
}
}
public interface IProduct
{
int ProductId { get; set; }
string Brand { get; set; }
string Model { get; set; }
decimal? Price { get; set; }
string Image { get; set; }
int CategoryId { get; set; }
Category Category { get; set; }
}
public class Phone: IProduct
{
public int ProductId { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
public string Brand { get; set; }
public string Model { get; set; }
public string network_technology { get; set; }
public string bands_2G { get;set; }
public string bands_3G{ get; set; }
public string bands_4G { get; set; }
public string network_speed { get; set; }
public string GPRS { get; set; }
public string EDGE { get; set; }
public string announced { get; set; }
public string status { get; set; }
public string dimentions { get; set; }
public float? weight_g { get; set; }
public float? weight_oz { get; set; }
public string SIM { get; set; }
public string display_type { get; set; }
public string display_resolution { get; set; }
public string display_size { get; set; }
public string OS { get; set; }
public string CPU { get; set; }
public string Chipset { get; set; }
public string GPU { get; set; }
public string memory_card { get; set; }
public string internal_memory { get; set; }
public string RAM { get; set; }
public string primary_camera { get; set; }
public string secondary_camera { get; set; }
public string loud_speaker { get; set; }
public string audio_jack { get; set; }
public string WLAN { get; set; }
public string bluetooth { get; set; }
public string GPS { get; set; }
public string NFC { get; set; }
public string radio { get; set; }
public string USB { get; set; }
public string sensors { get; set; }
public string battery { get; set; }
public string colors { get; set; }
public decimal? Price { get; set; }
public string Image { get; set; }
}
I don't know what am I doing wrong but after I update the database from nuget console, a new Category record is created per seeded product(phone). That's exactly the opposite of what I want. I want all the phones to have one categoryId that refers to Phones category. does anyone know what's wrong?
Entity Type Configurations (fluent api):
public class CategoryConfiguration : EntityTypeConfiguration<Category>
{
public CategoryConfiguration()
{
ToTable("Categories");
HasKey(m => m.CategoryId);
}
}
public class PhoneConfiguration : EntityTypeConfiguration<Phone>
{
public PhoneConfiguration()
{
ToTable("Phones");
HasKey(m => m.ProductId);
}
}
Seed method:
protected override void Seed(BestPhone.Data.BestPhoneDbContext context)
{
context.Categories.AddOrUpdate(new Category(){Name = "Phones", CategoryId = 1});
...
//getting records from a csv file and holding them in an array.
var records = csvReader.GetRecords<Phone>().ToArray();
foreach (var record in records)
{
record.CategoryId = 1;
}
context.Phones.AddRange(records);
context.SaveChanges();
}
}
Try to add the next method on your CategoryConfiguration class:
public void Configure(EntityTypeBuilder<Category> builder)
{
builder
.HasMany(s => s.Products)
.WithOne(t => t.Category)
.HasForeignKey(t => t.CategoryId);
}
I'm not sure but it seems a system does not take into account your foreign key during seeding.

Entity framework not creating join table

I will appreciate if somebody can tell me why entity framework is not creating join table for following model. It is creating table for type and feature but not the table that will join them.
public class DeviceType
{
[Display(Name = "ID")]
public int DeviceTypeID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public IEnumerable<DeviceFeature> DeviceFeatures { get; set; }
}
public class DeviceFeature
{
[Display(Name = "ID")]
public int DeviceFeatureID { get; set; }
[Required]
public string Name { get; set; }
public string Description { get; set; }
public IEnumerable<DeviceType> DeviceTypes { get; set; }
}
public class DeviceFeatureView
{
public virtual IEnumerable<DeviceType> DeviceTypes { get; set; }
public virtual IEnumerable<DeviceFeature> DeviceFeatures { get; set;
}
You do not need the bridge to create a many-to-many relationship. EF will figure it out. Change the type of the navigation properties from IEnumerable to ICollection like this:
public class DeviceType
{
public DeviceType()
{
this.DeviceFeatures = new HashSet<DeviceFeature>();
}
[Display(Name = "ID")]
public int DeviceTypeID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<DeviceFeature> DeviceFeatures { get; set; }
}
public class DeviceFeature
{
public DeviceFeature()
{
this.DeviceTypes = new HashSet<DeviceType>();
}
[Display(Name = "ID")]
public int DeviceFeatureID { get; set; }
[Required]
public string Name { get; set; }
public string Description { get; set; }
public ICollection<DeviceType> DeviceTypes { get; set; }
}
More about it here.

Form with list of lists

I have been struggling with what seems to me to be a simple thing. I need to create a form with list of lists.
This is the model that I want to make a form of:
public OrderViewModel()
{
DeliveryAddress = new ProjectDeliveryAddressViewModel();
OrderItems = new List<OrderItemView>();
}
public int ProjectDeliveryId { get; set; }
public long ProjectId { get; set; }
[Display(ResourceType = typeof(Res.ViewModels.Common), Name = "CustomerOrderNumber")]
public string CustomerOrderNumber { get; set; }
[Display(ResourceType = typeof(Res.ViewModels.Common), Name = "DeliveryDate")]
public string RequestedDeliveryDate { get; set; }
public ProjectDeliveryAddressViewModel DeliveryAddress { get; set; }
public IList<OrderItemView> OrderItems { get; set; }
}
public class OrderItemView
{
public OrderItemView()
{
Additionalitems = new List<AdditionalItem>();
}
public long ProjectItemId { get; set; }
public string ItemName { get; set; }
public string ImageData { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
public string AaCompany { get; set; }
public string SupplierName { get; set; }
public int SupplierModelId { get; set; }
public IList<AdditionalItem> Additionalitems { get; set; }
}
public class AdditionalItem
{
public string Name { get; set; }
public string Id { get; set; }
public bool Value { get; set; }
public decimal Price { get; set; }
public int Quantity { get; set; }
}
What is the simplest way of doing this so that I can easily post the form to my mvc controller later on?

How to order by another model's value in ASP.NET MVC3

OverstockEntities.cs
namespace Overstock.Models
{
public class OverstockEntities: DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
}
}
Product.cs
namespace Overstock.Models
{
[Bind(Exclude = "ProductId")]
public class Product
{
[ScaffoldColumn(false)]
public int ProductId { get; set; }
[DisplayName("Category")]
public int CategoryId { get; set; }
[DisplayName("Brand")]
public int BrandId { get; set; }
[Required(ErrorMessage="Product title is required")]
[StringLength(160)]
public string Title { get; set; }
[Required(ErrorMessage="Price is required")]
[Range(0.01, 100000.00,
ErrorMessage="Price must be between 0.01 and 100000.00")]
public decimal Price { get; set; }
[DisplayName("Product Art URL")]
[StringLength(1024)]
public string PictureUrl { get; set; }
[Required(ErrorMessage = "Description is required")]
[StringLength(1024)]
public string Description { get; set; }
public virtual Category Category { get; set; }
public virtual Brand Brand { get; set; }
public virtual List<OrderDetail> OrderDetails { get; set; }
}
}
Category.cs
namespace Overstock.Models
{
public class Category
{
public int CategoryId { get; set; }
public string Name { get; set; }
public List<Product> Products { get; set; }
}
}
Browse action
public ActionResult Browse(string category, string sortOrder)
{
var varCategories = MyDB.Categories.Include("Products").Single(c => c.Name == category);
//How to order by Product's Title value
return View(varCategories);
}
Question: how to get another model's variable(in this case Product.Title) in order to sort by that variable?
foreach (var category in varCategories )
{
category.Products = category.Products.OrderBy(p => p.Title);
}

Categories