Create method doesn't store - c#

namespace Teatastic.Models
{
public class Tea
{
[Key]
public int Id { get; set; }
[Required]
[StringLength(100)]
[DataType(DataType.Text)]
public string Name { get; set; }
[Required]
public double Price { get; set; }
//Relationships
public List<Function>? Functions { get; set; }
[NotMapped]
public List<int> FunctionIds { get; set; }
public int BrandId { get; set; }
public Brand Brand { get; set; }
}
}
using Microsoft.Extensions.Hosting;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Drawing;
namespace Teatastic.Models
{
public class Brand
{
public int Id { get; set; }
[Required]
[StringLength(100)]
[DataType(DataType.Text)]
public string Name { get; set; }
[NotMapped]
public Image? Logo { get; set; }
public List<Tea>? Teas{ get; set; }
}
}
Finally, this is the HttpPost method in the TeasController
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Name,Price,FunctionIds,BrandId")] Tea tea)
{
if (ModelState.IsValid)
{
if (tea.Functions == null)
{
tea.Functions = new List<Function>();
}
foreach (int FunctionId in tea.FunctionIds)
{
tea.Functions.Add(_context.Function.FirstOrDefault(f => f.Id == FunctionId));
}
// Add brand to tea
tea.Brand = _context.Brands.FirstOrDefault(b => b.Id == tea.BrandId);
_context.Add(tea);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(tea);
}
enter image description here
There is a one-to-many relationship between Tea and Brand (every tea has a brand, a brand can have multiple teas). I am trying to store this object in the database, but it appears that there is something wrong with the Brand.

You may use .NET 6/.NET 7. From .NET 6 the non-nullable property must be required, otherwise the ModelState will be invalid.
Add ? to your Brand property:
public class Tea
{
[Key]
public int Id { get; set; }
[Required]
[StringLength(100)]
[DataType(DataType.Text)]
public string Name { get; set; }
[Required]
public double Price { get; set; }
//Relationships
public List<Function>? Functions { get; set; }
[NotMapped]
public List<int> FunctionIds { get; set; }
public int BrandId { get; set; }
public Brand? Brand { get; set; }
}

Related

How to create a relation between existing entities in EF core?

I have a case scenario with two tables References and Products alreading containing many entries which can be dynamically related on demand.
public class Reference
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid ReferenceId { get; set; }
public string Name { get; set; }
public string Status { get; set; }
public virtual ICollection<Product> ManyProducts { get; set; }
public Reference() {}
}
public class Product
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
[ForeignKey("Reference")]
public Guid ReferenceId { get; set; }
public virtual Reference OneReference { get; set; }
public Product() {}
}
When a user ask to link a reference to a product I simply do :
product.ReferenceId = reference.ReferenceId ;
await context.SaveChangesAsync() ;
The entry in Products table is updated correctly, but when I try to access a reference's related data, it does not retrieve any ?? After eager loading :
var reference = await context.References
.Include(r => r.ManyProducts)
.SingleAsync(r => r.ReferenceId == referenceId) ;
or explicit loading :
var reference = await context.References.FindAsync(referenceId) ;
await context.Entry(reference).Collection(s => s.ManyProducts).LoadAsync() ;
reference.ManyProducts is empty. So I have to do something like this :
var reference = await context.References.FindAsync(referenceId) ;
var products = await context.Products.Where(l => l.ReferenceId == referenceId).ToListAsync() ;
result.ManyProducts = products ;
which works fine, but I would like to understand why ?
I´m using DataAnnotation
Sample
public class spread
{
[Key]
public int spreadid { get; set; }
[Required]
public DateTime insertdate { get; set; }
[Required]
public int exchangeid { get; set; }
[ForeignKey("exchangeid"), Display(Name = "Exchange origem")]
public virtual exchange exchange { get; set; } // One to one
[ForeignKey("spreadid")]
public virtual ICollection<spreadhelper> spreadhelper { get; set; } // One to many
}
public class spreadhelper
{
[Key]
public int spreadhelperid { get; set; }
[Required]
public int spreadid { get; set; }
[Required]
public int exchangeid { get; set; }
[ForeignKey("exchangeid"), Display(Name = "Exchange")] // One to one
public virtual exchange exchange { get; set; }
[Required, Range(0, 200)]
public decimal spreadvalue { get; set; }
}
one to one - sample
public class exchange
{
[Key]
public int exchangeid { get; set; }
[Required]
public DateTime insertdate { get; set; }
[Required, MaxLength(50)]
public string name { get; set; }
[MaxLength(128)]
public string token { get; set; }
}
One to many sample

Foreign Key Issue?

In my HomeController, I am having trouble with my create function accessing the database. After submitting the form in my browser, this is the error that shows:
Error Given
MySqlException: Cannot add or update a child row: a foreign key constraint fails (petshelterdb.pets, CONSTRAINT FK_Pets_Owners_OwnerId FOREIGN KEY (OwnerId) REFERENCES owners (OwnerId) ON DELETE CASCADE)
MySqlConnector.Core.ResultSet.ReadResultSetHeaderAsync(IOBehavior ioBehavior) in ResultSet.cs, line 49
I am not using a login/registration. The idea is that I have a "bulletin board" that shows pets that can be adopted and owners that can adopt. A new pet or owner can be added to the board. If I select the owner's name, I can have that owner "adopt" a pet on the board. I designated in the HomeController code which line is the issue.
Since I'm not working with a UserId, I'm not sure how to go about this.
Pet.cs
namespace petShelter.Models
{
public class Pet
{
[Key]
public int PetId { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Type { get; set; }
[Required]
public string Description { get; set; }
public string Skill1 { get; set; }
public string Skill2 { get; set; }
public string Skill3 { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
public Owner Owner { get; set; }
public int OwnerId { get; set; }
}
}
Owner.cs
namespace petShelter.Models
{
public class Owner
{
[Key]
public int OwnerId { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
List<Pet> MyPets { get; set; }
public string FullName()
{
return FirstName + " " + LastName;
}
}
}
HomeController.cs
[HttpPost("/pet/new")]
public IActionResult Create(Pet newPet)
{
if (ModelState.IsValid)
{
_context.Add(newPet);
_context.SaveChanges(); ***THIS IS WHERE ISSUE OCCURS***
return RedirectToAction("Index", new { id = newPet.PetId });
}
else
{
if (newPet.Name == null)
{
ModelState.TryAddModelError("Name", "The Name field is required");
}
return View("NewPet", newPet);
}
}
PetShelterContext.cs
namespace petShelter.Models
{
public class PetShelterContext : DbContext
{
public PetShelterContext(DbContextOptions options) : base(options) { }
public DbSet<Pet> Pets { get; set; }
public DbSet<Owner> Owners { get; set; }
}
}
Replace
public int OwnerId { get; set; }
with
public int? OwnerId { get; set; }
and fix properties ( the attributes are optional for net5)
public class Owner
{
.......
[InverseProperty(nameof(Pet.Owner))]
public virtual ICollection<Pet> Pets { get; set; }
.....
}
and maybe here too
public class Pet
{
.....
public int OwnerId { get; set; }
[ForeignKey(nameof(OwnerId))]
[InverseProperty("Pets")]
public Owner Owner { get; set; }
}

EF Code First One To Many

How can I get a class to have a collection composed of another model, and have that be populated when I fetch my original model. I have a Wishlist, and there are 0 or many products inside that wishlist. What does my data annotation or fluent API need to say in order for that to populate if I were to do a db.Wishlist.find(id). Here is what I currently have in my wishlist model
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Models
{
[Table("Wishlist")]
public class Wishlist
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[ScaffoldColumn(false)]
public int ID { get; set; }
[StringLength(100)]
public string Name { get; set; }
public int ProductID { get; set; }
public virtual ICollection<Product> Product { get; set; }
public int CustomerID { get; set; }
[Required]
public Customer Customer { get; set; }
public virtual List<Product> Products { get; set; }
[DisplayFormat(DataFormatString = "{0:f}")]
public DateTime CreateDate { get; set; }
[DisplayFormat(DataFormatString = "{0:f}")]
public DateTime LastModifiedDate { get; set; }
}
}
what is required to get the products to populate as either a collection or as a list. What is the correct approach to achieving this? I'm aware one of the collections of products must go, just not sure which and what is needed.
UPDATE: added display of my product model.
namespace Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
[Table("Product")]
public partial class Product
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Product()
{
OrderLines = new HashSet<OrderLine>();
SKU_Table = new HashSet<Sku>();
XREF_CatalogProduct = new HashSet<XREF_CatalogProduct>();
ProductImages = new List<ProductImage>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[NotMapped]
public string FormattedPrice { get { return this.Price.ToString("C"); } }
[Required]
[MaxLength]
public string PageURL { get; set; }
[Required]
[StringLength(250)]
public string Name { get; set; }
[Required]
public string Code { get; set; }
public string Description { get; set; }
public int CategoryID { get; set; }
[Column(TypeName = "money")]
[DisplayFormat(DataFormatString = "${0:#,0}", ApplyFormatInEditMode = true)]
public decimal Price { get; set; }
public DateTime? DateCreated { get; set; }
public DateTime? DateModified { get; set; }
[Required]
public bool Featured { get; set; }
public virtual string ImagePath { get; set; }
public virtual Category Category { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<OrderLine> OrderLines { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Sku> SKU_Table { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<XREF_CatalogProduct> XREF_CatalogProduct { get; set; }
public virtual ICollection<ProductImage> ProductImages { get; set; }
}
}
You have to setup a M: M relationship with the Wishlist : Product.Code first will create a Junction table for you if you use DataAnnotation.
Using DataAnnotation :
[Table("Wishlist")]
public class Wishlist
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[ScaffoldColumn(false)]
public int ID { get; set; }
[StringLength(100)]
public string Name { get; set; }
public int CustomerID { get; set; }
[Required]
public Customer Customer { get; set; }
[DisplayFormat(DataFormatString = "{0:f}")]
public DateTime CreateDate { get; set; }
[DisplayFormat(DataFormatString = "{0:f}")]
public DateTime LastModifiedDate { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
And
[Table("Product")]
public partial class Product
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Product()
{
OrderLines = new HashSet<OrderLine>();
SKU_Table = new HashSet<Sku>();
XREF_CatalogProduct = new HashSet<XREF_CatalogProduct>();
ProductImages = new List<ProductImage>();
this.Wishlists = new HashSet<Wishlist>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[NotMapped]
public string FormattedPrice { get { return this.Price.ToString("C"); } }
[Required]
[MaxLength]
public string PageURL { get; set; }
[Required]
[StringLength(250)]
public string Name { get; set; }
[Required]
public string Code { get; set; }
public string Description { get; set; }
public int CategoryID { get; set; }
[Column(TypeName = "money")]
[DisplayFormat(DataFormatString = "${0:#,0}", ApplyFormatInEditMode = true)]
public decimal Price { get; set; }
public DateTime? DateCreated { get; set; }
public DateTime? DateModified { get; set; }
[Required]
public bool Featured { get; set; }
public virtual string ImagePath { get; set; }
public virtual Category Category { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<OrderLine> OrderLines { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Sku> SKU_Table { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<XREF_CatalogProduct> XREF_CatalogProduct { get; set; }
public virtual ICollection<ProductImage> ProductImages { get; set; }
public virtual ICollection<Wishlist> Wishlists { get; set; }
}
EF Query : to retrieve wishlist according to the product Id
var prod_id=1; // your product id
var query= from wishlist in db.Wishlists
where wishlist.Products.Any(c=>c.Product_ID== prod_id)
select wishlist;
Using Fluent Api :
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Wishlist>()
.HasMany<Product>(s => s.Products)
.WithMany(c => c.Wishlists)
.Map(cs =>
{
cs.MapLeftKey("WishlistRefId");
cs.MapRightKey("ProductRefId");
cs.ToTable("WishlistProduct");
});
}
EF Query : to retrieve wishlist according to the product Id
var prod_id=1; // your product id
var query= from wishlist in db.Wishlists
where wishlist.Products.Any(c=>c.ProductRefId == prod_id)
select wishlist;

How to fix "One or more validation errors were detected during model generation"-error [duplicate]

This question already has answers here:
EntityType has no key defined error
(13 answers)
Closed 4 years ago.
One or more validation errors were detected during model generation:
SportsStore.Domain.Concrete.shop_Products: : EntityType 'shop_Products' has no key defined. Define the key for this EntityType.
Products: EntityType: EntitySet 'Products' is based on type 'shop_Products' that has no keys defined.
public ViewResult Index()
{
ProductsListViewModel viewModel = new ProductsListViewModel
{
Products = repository.Products
.Where(p => p.CategoryId == 100)
.OrderByDescending(p=>p.ProductID)
.Take(5)
};
return View(viewModel);
}
#foreach (var p in Model.Products)
{
#p.ProductName
}
public class shop_Products {
public int ProductID { get; set; }
public string ProductName { get; set; }
public int CategoryId { get; set; }
public Nullable<int> CategoryPropertyId { get; set; }
public string PropertyValue { get; set; }
public Nullable<int> ProductBrandId { get; set; }
public Nullable<decimal> MarketPrice { get; set; }
public decimal Price { get; set; }
public Nullable<decimal> UserPrice { get; set; }
public string TitleKeyword { get; set; }
public string MetaKeyword { get; set; }
public string MetaDescription { get; set; }
public string PhotoName { get; set; }
public string PhotoPath { get; set; }
public string smallPhotos { get; set; }
public string BigPhotos { get; set; }
public string URL { get; set; }
public double Discount { get; set; }
public int Inventory { get; set; }
public string ShortDesc { get; set; }
public bool IsAccessories { get; set; }
public bool IsGroup { get; set; }
public bool IsTopService { get; set; }
public string Accessorices { get; set; }
public string PeopleGroup { get; set; }
public string TopService { get; set; }
public string Contents { get; set; }
public string Parameter { get; set; }
public string PackingList { get; set; }
public string Service { get; set; }
public string Professional { get; set; }
public bool IsParameter { get; set; }
public bool IsPackingList { get; set; }
public bool IsService { get; set; }
public bool IsProfessional { get; set; }
public Nullable<bool> IsEnable { get; set; }
public Nullable<bool> IsCommend { get; set; }
public Nullable<bool> IsTop { get; set; }
public Nullable<bool> IsBest { get; set; }
public string ProductBrandType { get; set; }
public string Manufacturer { get; set; }
public string Makein { get; set; }
public string weight { get; set; }
public System.DateTime InputTime { get; set; }
public Nullable<int> Sort { get; set; }
public Nullable<int> SeeCount { get; set; }
}
I made a few of these,and works well.But these is wrong.Can anybody help me?
By convention EF uses either the field Id or [type name]Id as a Primary Key. See here: http://msdn.microsoft.com/en-us/library/system.data.entity.modelconfiguration.conventions.idkeydiscoveryconvention%28v=vs.103%29.aspx
The fact that your type is named shop_Products but you have the key set to ProductID (assumption) means it cant find one by convention. So you can either change the field name or type name or add the data annotation [Key] above ProductID like so:
[Key]
public int ProductID { get; set; }
Add this namespace ref System.ComponentModel.DataAnnotations to your model and then add the [Key] annotation above your id property
namespace: using System.ComponentModel.DataAnnotations.Schema;
[Key] public int ProductID { get; set; }
you can also just rename productID to id
public int id {get; set;}
Here is my code for this type of problem in asp.net mvc
before
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace glostars.Models
{
public class WeeklyTagged
{
public int TaggedId { get; set; }
}
}
after
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; //added this line
using System.Linq;
using System.Web;
namespace glostars.Models
{
public class WeeklyTagged
{
[Key] //and this line
public int TaggedId { get; set; }
}
}
And now it works. Thank you

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