I am working on a Restaurant Application. I have a restaurant model and a table model.
namespace Restaurant.Models
{
[Table("Restaurant")]
public class RestaurantModel
{
[Key]
[Column("id")]
public int Id { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("telephone_number")]
public int TelephoneNumber { get; set; }
[NotMapped]
public List<TableModel> Tables;
public RestaurantModel()
{
Tables = new List<TableModel>();
}
}
}
namespace Restaurant.Models
{
[Table("Table")]
public class TableModel
{
[Key]
[Column("id")]
public int Id { get; set; }
[ForeignKey("restaurant_id")]
[Required] [NotNull]
public int RestaurantId { get; set; }
[Column("available_seats")]
public int AvailableSeats { get; set; }
[Column("is_indoors")]
public bool IsIndoors { get; set; }
}
}
I have a dependency between Restaurant and Table:
Here are the columns and keys that Entity Framework has created for me via my context:
Lastly, here's my Context class:
namespace Restaurant.Data
{
public class RestaurantContext : DbContext
{
public RestaurantContext(DbContextOptions<RestaurantContext> options) : base(options)
{
}
public DbSet<RestaurantModel> Restaurants { get; set; }
public DbSet<TableModel> Tables { get; set; }
public DbSet<GuestModel> Guests { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<RestaurantModel>().ToTable("Restaurant");
modelBuilder.Entity<TableModel>().ToTable("Table");
modelBuilder.Entity<GuestModel>().ToTable("Guest");
modelBuilder.Entity<TableModel>()
.HasOne<RestaurantModel>();
}
}
}
When I retrieve a restaurant, I want the corresponding tables to be retrieved inside of the TableModel List. Currently, when I retrieve a Restaurant, it will not retrieve any corresponding Tables. This makes sense to me, as I have not properly connected the relationship for EntityFramework to recognize it. I have tried to look online how to do it, consulting guides on setting up Foreign Key relationships and such. I cannot find the information I am looking for, due to a lack of basic knowledge. The answers I can find do not make sense to me because I do not understand what they are doing or how they are doing it.
Could anyone point me in the right direction or tell me what I am doing wrong?
add relations to your classes
[Table("Restaurant")]
public class Restaurant
{
[Key]
[Column("id")]
public int Id { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("telephone_number")]
public int TelephoneNumber { get; set; }
public virtual ICollection<Table> Tables { get; set; }
}
}
[Table("Table")]
public class Table
{
[Key]
[Column("id")]
public int Id { get; set; }
public int? RestaurantId { get; set; }
public virtual Restourant Restaurant { get; set; }
[Column("available_seats")]
public int AvailableSeats { get; set; }
[Column("is_indoors")]
public bool IsIndoors { get; set; }
}
}
and since you are using Net core 5+ I don' t think that you any navigation attributes or fluent APIs
Delete old migration folde and make a clean migration to db
after this you can try this code for test
var restourant= context.Restourants.Include(r=> r.Tables).FirstOrDefault(r=>r.Id==id);
it should return a restourant with a list of tables
Related
Given two tables, TrackingTag and TrackingTagStatusUpdate:
public class TrackingTag
{
public int ID { get; set; }
}
public class TrackingTagStatusUpdate
{
public int ID { get; set; }
public int TrackingTagID { get; set; }
public TrackingTag TrackingTag { get; set; }
public int Epoch { get; set; } //32-bit
[MaxLength(32)]
public string APConnectedSSID { get; set; }
}
As there will be many TrackingTagStatusUpdates, I want to add a field "LatestStatusUpdate" to TrackingTag, for performance reasons.
public class TrackingTag
{
public int ID { get; set; }
public int? LatestStatusUpdateID { get; set; }
public TrackingTagStatusUpdate LatestStatusUpdate { get; set; }
}
LatestStatusUpdate is optional, as it may not be set if there are not yet any Status Updates for the Tag.
Entity Framework Core complains that "The child/dependent side could not be determined for the one-to-one relationship between 'TrackingTag.LatestStatusUpdate' and 'TrackingTagStatusUpdate.TrackingTag'.". I then add
modelBuilder.Entity<TrackingTag>().HasOne(x => x.LatestStatusUpdate).WithOne(x => x.TrackingTag).HasForeignKey<TrackingTagStatusUpdate>(x => x.TrackingTagID);
to OnModelCreating(ModelBuilder modelBuilder), however this results in Entity Framework Core creating a relationship with a Unique constraint, which will not work as there will be many TrackingTagStatusUpdate with the same TrackingTagID.
How do I do this correctly?
This seems to have worked:
public class TrackingTag
{
public int ID { get; set; }
[ForeignKey(nameof(LatestStatusUpdate))]
public int? LatestStatusUpdateID { get; set; }
public TrackingTagStatusUpdate LatestStatusUpdate { get; set; }
}
I'm not sure how to achieve the same with the Fluent API though.
I recently needed to change the type of three properties in a model class from string to an ICollection custom type as shown below.
There are also three classes (SpecialType, TypeToAdd, TypeToRemove) that were added that have a primary key ID, name (string), qty (int) and a FK to corresponding Subscriptions_Regular_Id.
I ran the migration, then update-database to script, but when I ran the script in SSMS console it left off the three ICollection properties below. It did create the three dependent tables with their foreign keys back to the parent, but I can't understand why it's not creating these three ICollection properties. Something simple I'm overlooking I'm sure and wanted to get some input if anyone might have a suggestion.
public class Subscriptions
{
[Key]
public int Subscriptions_Regular_Id { get; set; }
public string CustomerNumber { get; set; }
public string Type { get; set; }
public int TypeQty { get; set; }
public ICollection<SpecialType> SpecialType { get; set; }
public ICollection<TypeToAdd> TypeToAdd { get; set; }
public ICollection<TypeToRemove> TypeToRemove { get; set; }
}
For context:
Subscriptions can have many SpecialTypes, TypeToAdd, and TypeToRemove
SpecialTypes, TypeToAdd, TypeToRemove can be tied to only one Subscription.
Thanks in advance for any input.
====== EDIT ======
Adding 3 ICollection classes:
public class TypeToAdd
{
[Key]
public int TypeToAddId { get; set; }
public string TypeToAdd { get; set; }
public int Qty { get; set; }
public int Subscriptions_Regular_Id { get; set; }
public Subscriptions Subscriptions { get; set; }
}
The other two classes are the same as above other than the first two property names (they are TypeToRemove and SpecialType).
but I can't understand why it's not creating these three ICollection properties
Collection Navigation Properties are implemented using seperate tables with foreign keys. Relational databases don't have multi-valued attributes, so that's just how related collections are implemented in an RDBMS.
Try to change the classes to this
public class Subscription
{
[Key]
public int Id { get; set; }
public string CustomerNumber { get; set; }
public string Type { get; set; }
public int TypeQty { get; set; }
[InverseProperty(nameof(TypeToAdd.Subscription))]
public ICollection<TypeToAdd> TypeToAdds { get; set; }
[InverseProperty(nameof(SpecialType.Subscription))]
public virtual ICollection<SpecialType> SpecialTypes { get; set; }
[InverseProperty(nameof(TypeToRemove.Subscription))]
public ICollection<TypeToRemove> TypeToRemoves { get; set; }
}
public class TypeToAdd
{
[Key]
public int Id { get; set; }
public string TypeToAdd { get; set; }
public int Qty { get; set; }
public int SubscriptionId { get; set; }
[ForeignKey(nameof(SubscriptionId))]
[InverseProperty("TypeToAdds")]
public virtual Subscription Subscription { get; set; }
}
SpecialType and TypeToRemove classes should be configured the same way as TypeToAdd.
I reproduced a simple example of a problem I have with Entity Framework.
I want to have three tables:
Users, Projects, WorkOrders
Table Users has information about users for all other tables (in example only two). WorkOrders has information about which User has to work on this work order and to which Project it belongs.
Here are the classes:
public class User
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<WorkOrder> WorkOrders { get; set; }
public virtual ICollection<Project> Projects { get; set; }
}
public class Project
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int ManagerId { get; set; }
public DateTime Start { get; set; }
public virtual User Manager { get; set; }
public virtual ICollection<WorkOrder> WorkOrders { get; set; }
}
public class WorkOrder
{
[Key]
public int Id { get; set; }
public int Number { get; set; }
public string Type { get; set; }
public int AssigneeId { get; set; }
public int ProjectId { get; set; }
public virtual Project Project { get; set; }
public virtual User Assignee { get; set; }
}
When I try to run the program, it throws an exception:
'Introducing FOREIGN KEY constraint 'FK_dbo.WorkOrders_dbo.Projects_ProjectId' on table 'WorkOrders' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Then I went another way. I tried DB-first approach with EF. I first created the tables and connections in SQL Server Management Studio:
Then the generated models by EF look almost the same as mine, with code-first approach.
public partial class User
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public User()
{
this.Project = new HashSet<Project>();
this.WorkOrder = new HashSet<WorkOrder>();
}
public int Id { get; set; }
public string Name { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Project> Project { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<WorkOrder> WorkOrder { get; set; }
}
public partial class Project
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Project()
{
this.WorkOrder = new HashSet<WorkOrder>();
}
public int Id { get; set; }
public string Name { get; set; }
public int ManagerId { get; set; }
public System.DateTime Start { get; set; }
public virtual User User { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<WorkOrder> WorkOrder { get; set; }
}
public partial class WorkOrder
{
public int Id { get; set; }
public int Number { get; set; }
public string Type { get; set; }
public int AssigneeId { get; set; }
public int ProjectId { get; set; }
public virtual Project Project { get; set; }
public virtual User User { get; set; }
}
So the code is almost identical, except the SuppressMesages and constructors in WorkOrder and User classes. The second approach works.
I would like to know, what makes the difference? Also the context class is identical as my own. Where or how are defined this FK constraints or cascade delete settings?
It is unfortunate default behavior of EF code first to crate FK with on delete cascade. So while defining relations you need to simply change this setting:
//in context
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Entity<Project>()
.HasRequired<User>(s => s.User)
.WithMany()
.WillCascadeOnDelete(false);
Also there might be a convention for it in modelBuilder.Conventions if you want to just change behavior for all FK.
I'm having some troubles when saving in the database a model with a little complex relationship.
The UML of the classes is:
The classes definition are:
public abstract class EntityBase
{
public virtual Guid Id { get; set; }
}
public class LoanRequest : EntityBase
{
[Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public virtual Applicant Applicant1 { get; set; }
public virtual Applicant Applicant2 { get; set; }
}
public class Applicant
{
[Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public Guid LoanRequestId { get; set; }
[ForeignKey("LoanRequestId")]
public virtual LoanRequest LoanRequest { get; set; }
public virtual ICollection<MonthlyIncome> Incomes { get; set; }
}
public class MonthlyIncome
{
[Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public Guid ApplicantId { get; set; }
[ForeignKey("ApplicantId")]
public virtual Applicant Applicant { get; set; }
}
I'm able to run a migration and looking into the database the tables and columns created by the framework seems fine to me. But, when saving an exception happens. The exception is:
Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values
I've been searching for a solution on the internet and I can't see where my problem is. Any suggestions? Thanks!
After several tryings I was able to find a solution. Changing the applicant definition to:
public class Applicant
{
[Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public virtual ICollection<MonthlyIncome> Incomes { get; set; }
}
was all I needed
I have the following table,
Id
EntityType
EntityId
Message
Depending on what the EntityType is, it will be mapped to a different table
if the EntityType is 1, then the Mapping Table is Table1
if the EntityType is 2, then the Mapping table is Table2
How can I create a a map configuration in Entity frame work?
I am using MVC4 and EF5
I had a similar design question and I couldn't find a (clean) way with EF to do it. If you think about the underlying database, it would be single field that is a foreign key that would reference different tables - is that even possible?
There are two alternative approaches that I can suggest. First, you could define optional relationships:
public class EntityTypeMap
{
public int Id { get; set; }
public virtual EntityType1 EntityType1 { get; set; }
public int? EntityType1Id { get; set; }
public virtual EntityType2 EntityType2 { get; set; }
public int? EntityType2Id { get; set; }
public string Message { get; set; }
}
The second (better) option is to create separate models, but derive from the same base class:
public class BaseMap
{
public int Id { get; set; }
public string Message { get; set; }
}
public class EntityType1Map : BaseMap
{
public virtual EntityType1 EntityType1 { get; set; }
public int? EntityType1Id { get; set; }
}
public class EntityType2Map : BaseMap
{
public virtual EntityType2 EntityType2 { get; set; }
public int? EntityType1Id { get; set; }
}