EF Code First One To Many - c#

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;

Related

How to add a foreign key into a table using one-to-one relationship in ASP.NET Core 6 Web API?

I am new to ASP.NET, how can I make my item table save the categoryID which I get from the category table? As an example I want the item "Apple mobile phone" to have the category ID which refers to category name which is electronics, I hope you got the picture.
Here is model:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace WebApplication1.Models
{
public class itemTable
{
[Key]
public int Id { get; set; }
public string company { get; set; }
public string availability { get; set; }
public decimal price { get; set; }
public decimal discount { get; set; }
public decimal tax { get; set; }
public string description { get; set; }
public int categoryid { get; set; }
}
public class categories
{
[Key]
public int categoryID { get; set; }
public string categoryName { get; set; }
}
}
And here is my DbContext:
using Microsoft.EntityFrameworkCore;
using System.Diagnostics;
using WebApplication1.Models;
namespace WebApplication1.Context
{
public class itemTableDbContext : DbContext
{
public itemTableDbContext(DbContextOptions options) : base(options)
{
}
public DbSet<itemTable> ItemTables { get; set; }
public DbSet<categories> categories { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<itemTable>().ToTable("itemtable");
modelBuilder.Entity<categories>().ToTable("categories");
}
}
}
I tried all the possible ways but there is always something wrong, multiple items might be in the same category like phone brand items are all under the "electronics" category
You can configure One-to-One relationship between two entities in such way:
public class ItemTable
{
[Key]
public int Id { get; set; }
public string Company { get; set; }
public string Availability { get; set; }
public decimal Price { get; set; }
public decimal Discount { get; set; }
public decimal Tax { get; set; }
public string Description { get; set; }
public virtual Category Category { get; set; }
}
public class Category
{
[Key]
[ForeignKey("ItemTable")]
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public virtual ItemTable ItemTable { get; set; }
}
Note: Better to use PascalCase in C#

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.

Query a many to may relationship with Linq [duplicate]

This question already has answers here:
Create code first, many to many, with additional fields in association table
(7 answers)
Closed 6 years ago.
I have a many to many relationship defined in my DB between User and Clinic tables. The database wasn't created using EF but I generated the DB model classes using EF. M-M relationship is usually created with EF by having collection object property of the of the linked classes defined within those classes but here I have an indirect relationship. Both User and Clinic models have UserClinic collection object instead of pointing directly to the other class.
Here's how the data objects are defined:
User
public User()
{
this.UserClinics = new HashSet<UserClinic>();
}
public long UsersID { get; set; }
public string AspNetUsersID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Organization { get; set; }
public string Title { get; set; }
public Nullable<System.DateTime> CreateDT { get; set; }
public Nullable<long> CreateBy { get; set; }
public Nullable<System.DateTime> UpdateDT { get; set; }
public Nullable<long> UpdateBy { get; set; }
public string Type { get; set; }
public string LoginID { get; set; }
public virtual AspNetUser AspNetUser { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<UserClinic> UserClinics { get; set; }
}
Clinic
public Clinic()
{
this.UserClinics = new HashSet<UserClinic>();
this.Patients = new HashSet<Patient>();
}
public long ClinicID { get; set; }
public Nullable<long> NetworkID { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public Nullable<System.DateTime> CreateDT { get; set; }
public Nullable<long> CreateBy { get; set; }
public Nullable<System.DateTime> UpdateDT { get; set; }
public Nullable<long> UpdateBy { get; set; }
public virtual Network Network { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<UserClinic> UserClinics { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Patient> Patients { get; set; }
}
UserClinic
public partial class UserClinic
{
public long UsersID { get; set; }
public long ClinicID { get; set; }
public Nullable<System.DateTime> CreateDT { get; set; }
public Nullable<long> CreateBy { get; set; }
public Nullable<System.DateTime> UpdateDT { get; set; }
public Nullable<long> UpdateBy { get; set; }
public virtual Clinic Clinic { get; set; }
public virtual User User { get; set; }
}
What's the best way to query objects so I get something to the effect of:
var cliniclist = user.clinics.toList();
or
var user.clinics.Add(clinicList);
To select you just need to select the UserClinics collection and then select the Clinic property from it:
var clinics = user.UserClinics.Select(x => x.Clinic);
To add:
user.UserClinics.Add(new UserClinic { ClinicID = 1, Clinic = new Clinic { ... } });

Entity Framework is not working in Entity Framework 5

Entity Framework is not working in Entity Framework 5.
Department class:
public partial class Department
{
public Department()
{
this.Courses = new HashSet<Course>();
}
public int DepartmentID { get; set; }
public string Name { get; set; }
public decimal Budget { get; set; }
public System.DateTime StartDate { get; set; }
public Nullable<int> InstructorID { get; set; }
public byte[] RowVersion { get; set; }
public virtual ICollection<Course> Courses { get; set; }
public virtual Person Person { get; set; }
}
Course class:
public partial class Course
{
public Course()
{
this.Enrollments = new HashSet<Enrollment>();
this.People = new HashSet<Person>();
}
public int CourseID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
public int DepartmentID { get; set; }
public byte[] rowversion { get; set; }
public virtual Department Department { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
public virtual ICollection<Person> People { get; set; }
}
Even Lazy loading and ProxyCreationEnabled are set to true. Please help me out

Can't seem to define composite foreign keys correctly in code-first entity framework

I have the following models in my solution:
internal class Customer
{
[Key]
public int CustomerId { get; set; }
[MaxLength(50)]
public string FirstName { get; set; }
[MaxLength(50)]
public string LastName { get; set; }
[MaxLength(12)]
public string PhoneNumber { get; set; }
}
internal class Product
{
[Key]
public int ProductId { get; set; }
[MaxLength(100)]
public string ProductName { get; set; }
public decimal Price { get; set; }
public double ProductWeight { get; set; }
public bool InStock { get; set; }
}
internal class Order
{
[Key]
public int OrderId { get; set; }
[ForeignKey("Customer")]
public int CustomerId { get; set; }
public Customer Customer { get; set; }
public DateTime OrderDate { get; set; }
[MaxLength(30)]
public string PoNumber { get; set; }
}
class Cart
{
public virtual ICollection<Order> Orders { get; set; }
public virtual ICollection<Product> Products { get; set; }
public uint Quantity { get; set; }
}
...and DB context
class Store : DbContext
{
public DbSet<Customer> Customers { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<Cart> Carts { get; set; }
}
When I debug, an exception is thrown saying "'Carts' is based on type 'Cart' that has no keys defined".
I've removed the Cart class from the DB context and the solution runs fine.
I've tried several different ways to declare the keys in the Cart class including:
[ForeignKey("Order")]
[Column(Order = 1)]
public int OrderId { get; set; }
public Order Order { get; set; }
[ForeignKey("Product")]
[Column(Order = 2)]
public int ProductId { get; set; }
public Product Product { get; set; }
or
[Key]
public int OrderId { get; set; }
[Key]
public int ProductId { get; set; }
Any ideas where I might be going wrong? (Please keep in mind this is an educational project so feedback on the DB design is unnecessary)

Categories