Simple model to demonstrate three types of relationships:
One-To-One - Deed and House: House has 1 deed and 1 deed is for that house
One-To-Many - House -> Room: My House has many rooms
Many-To-Many - Room <-> Color: The Many rooms can have many of the same colors
The classes (without the constructors):
public class Deed {
public int DeedId { get; set; }
public string Owner { get; set; }
public House Home { get; set; }
public class House
{
public int HouseId { get; set; }
public string Address { get; set; }
public List<Room> Rooms { get; set; }
public class Room
{
public int RoomId { get; set; }
public string Name { get; set; }
List<Color> Colors { get; set; }
public class Color
{
public int ColorId { get; set; }
public string ColorName { get; set; }
public List<Room> Rooms { get; set; }
My confusion is in the Migration UP constructors:
First the one to one: I get an error when Deed and House point to each other saying it cannot determine the "principle". So I made Deed the principle:
Next House has Many Rooms. I think I understand that the foreign key is ONLY in each room pointing back to the house like this:
Next is where I really get confused. I would expect the Many ROOMS share Many COLORS (many to many)... each would point to the other. BUT:
I appreciate your advice.
Thanks in advance,
Yogi ("Chuck")
Try this minor cleanup of your model. Also why wouldn't a House have multiple Deeds? And anyway EF6 makes it hard to model 1-1 relationships. You either have to make the DeedId the FK to House, or make Deed a Complex Type instead of an Entity.
public class Deed
{
public int DeedId { get; set; }
public string Owner { get; set; }
public int HouseId { get; set; }
public House House { get; set; }
}
public class House
{
public int HouseId { get; set; }
public string Address { get; set; }
public virtual ICollection<Room> Rooms { get; } = new HashSet<Room>();
}
public class Room
{
public int RoomId { get; set; }
public string Name { get; set; }
public int HouseId { get; set; }
public House House { get; set; }
public virtual ICollection<Color> Colors { get; } = new HashSet<Color>();
}
public class Color
{
public int ColorId { get; set; }
public string ColorName { get; set; }
public virtual ICollection<Room> Rooms { get; } = new HashSet<Room>();
}
public class MyDbContext : DbContext
{
public DbSet<Deed> Deeds { get; set; }
public DbSet<House> Houses { get; set; }
public DbSet<Room> Rooms { get; set; }
public DbSet<Color> Colors { get; set; }
}
Related
Let's say I have a bike shops that sell various types of bikes: pro, kids, youth, leisure and any mixture. So I have a table of shops that refers/relates to a table of possible types. Now these shops also host events with the same types: events for pros, kids etc again any mixture. And so I have another table of events that also need to refer/relate to the same table of types:
I need to be able in a single quick query get a list of all bike types for a shop or event.
So I figured I'd have 3 main tables: Shops, Events, BikeTypes and two intermediate to link shops and events to bike types:
And I organized my models as:
public class BikeShop
{
public long Id { get; set; }
public string name { get; set; }
public string address { get; set; }
public string phone { get; set; }
}
public class BikeEvent
{
public long Id { get; set; }
public string name { get; set; }
public string description { get; set; }
public DateTime date { get; set; }
public string location { get; set; }
}
public class BikeType
{
public long Id { get; set; }
public string name { get; set; }
public string code { get; set; }
}
public class ShopBikeTypes
{
public long Id { get; set; }
public BikeShop shop { get; set; }
public BikeType biketype { get; set; }
}
public class EventBikeTypes
{
public long Id { get; set; }
public BikeEvent bikeevent { get; set; }
public BikeType biketype { get; set; }
}
With DataCotext:
public class DataContext : DbContext
{
public DbSet<BikeShop> Shops { get; set; }
public DbSet<BikeEvent> Events { get; set; }
public DbSet<BikeType> BikeTypes { get; set; }
public DbSet<ShopBikeTypes> ShopBikeTypes { get; set; }
public DbSet<EventBikeTypes> EventBikeTypes { get; set; }
}
Migration creates correct database structure just as my diagram. Great!
Now how do I make a straight forward query:
get list of all bike types for a shop
get list of all bike types for an event
Is my structure even correct?
Do I need some List<> in the main object models BikeShop and BikeEvent?
EF's include and theninclude seem to require some list?
This feels like such a typical scenario. What's the right way of doing this?
Thank you.
Those are the linq queries that you are asked but when i look at that your class models, i can say they are wrong. U need to define first which relation theyre having. if all of that relation has based on one-to-one, u wont gonna need any List<> in your class models. but if u have one-to-many relation,u gonna need them.
1- get list of all bike types for a shop
return DbContext.Shops
.Include(x>=x.ShopBikeTypes)
.ThenInclude(x=>x.BikeTypes).ToList();
2- get list of all bike types for an event
return DbContext.Events
.Include(x=>x.EventBikeTypes)
.ThenInclude(x=>x.BikeTypes).ToList();
3- Get all data in that relation
return DbContext.BikeTypes
.Include(x>=x.EventBikeTypes)
.ThenInclude(x=>x.Events).AsSplitQuery()
.Include(x=>x.ShopBikeTypes)
.ThenInclude(x>=x.Shops).AsSplitQuery()
.ToList();
it can be a tough query, do not try to use AsNoTracking() because it can cause Cartesian Explosion.
#BerkGarip: thank you for your help. I ended up with this models structure:
public class AShop
{
public long Id { get; set; }
public string name { get; set; }
public string address { get; set; }
public string phone { get; set; }
public List<AShopType> aTypes { get; set; }
}
public class AEvent
{
public long Id { get; set; }
public string name { get; set; }
public string description { get; set; }
public DateTime date { get; set; }
public string location { get; set; }
public List<AEventType> aTypes { get; set; }
}
public class AType
{
public long Id { get; set; }
public string name { get; set; }
public string code { get; set; }
}
public class AShopType
{
public long Id { get; set; }
public AType aType { get; set; }
}
public class AEventType
{
public long Id { get; set; }
public AType aType { get; set; }
}
In order to achieve what I needed using answer from #BerkGarip I figured out that the trick there was to have lists in the 'shop' and 'event' models to the intermediate objects which in turn have a single reference to 'type'. This way database layout is the same and it is many-to-many relationship and I can use 'include' and 'thenInclude' exactly as expected:
return await _context.AShops.Where(x => x.name == "Z")
.Include(x => x.aTypes)
.ThenInclude(y => y.aType)
.ToListAsync();
I have a question regarding Many to Many tables using EF Core.
Assume I have the below situation:
public class Book
{
public int BookId { get; set; }
public string Title { get; set; }
public Author Author { get; set; }
public ICollection<BookCategory> BookCategories { get; set; }
}
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public ICollection<BookCategory> BookCategories { get; set; }
}
public class BookCategory
{
public int BookId { get; set; }
public Book Book { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
Now, assume that I want to have another table called "Contracts" which should be a child of "BookCategory".
How can I create this relationship?
I've seen plenty of examples not using Data Annotations and can get a one-to-one relationship working, but having difficulty with a one-to-many.
We have parts that we will randomly take sample weights on to make sure our machine house is producing to spec. The one-to-one relationship for Material will load. Having trouble with the QualityMeasurements one-to-many.
Anyone have experience with this?
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
public class Part {
[Key]
public string PartID { get; set; }
public string PartNumber { get; set; }
[ForeignKey("MaterialID")]
public virtual Material Material { get; set; }
public int MaterialID { get; set; }
[ForeignKey("PartNumber")]
public virtual ICollection<QualityMeasurement> Qualities { get; set; }
}
public class Material {
[Key]
public int MaterialID { get; set; }
public string Title { get; set; }
public double Density { get; set; }
}
public class QualityMeasurement {
public int QualityID { get; set; }
[Key]
public string PartNumber { get; set; }
public double UnitWeight { get; set; }
}
You are having troubles because in the one-to-many relationship, the foreign key should be defined at the many side and should relate to the primary key of the one side.
Your model should be something like this:
public class Part {
[Key]
public string PartID { get; set; }
public string PartNumber { get; set; }
[ForeignKey("MaterialID")]
public virtual Material Material { get; set; }
public int MaterialID { get; set; }
public virtual ICollection<QualityMeasurement> Qualities { get; set; }
}
public class QualityMeasurement {
[Key]
public int QualityID { get; set; }
[ForeignKey("PartID")]
public virtual Part Part { get; set; }
public string PartID { get; set; }
public double UnitWeight { get; set; }
}
I am designing a database for tests (say #school) and I am not sure how to go about the seeding the database (I am using the code-first approach and the models are as below)
My models are as follows:
Levels -> Subjects -> Chapters -> Questions -> Options
If I have to seed, I would need to create a level and a list of subjects, which in turn would need list of chapters which in turn would need list of questions and then list of options.
This is the code of the models:
//Level
public class Level
{
public Level()
{
Subjects = new List<Subject>();
}
public int id { get; set; }
public string Name { get; set; }
//Navigate
public virtual ICollection<Subject> Subjects { get; set; }
}
//Subject
public class Subject
{
public Subject()
{
Chapters = new List<Chapter>();
}
public int id { get; set; }
public string Name { get; set; }
public int LevelId { get; set; }
//Navigate
public virtual Level Level { get; set; }
public virtual ICollection<Chapter> Chapters { get; set; }
}
// Chapter
public class Chapter
{
public Chapter()
{
Questions = new List<Question>();
}
public int id { get; set; }
public string Name { get; set; }
public int SubjectId { get; set; }
public int LevelId { get; set; }
//Navigate
public virtual Subject Subject { get; set; }
public virtual Level Level { get; set; }
public virtual ICollection<Question> Questions { get; set; }
}
Any help would be appreciated
I created a WCF service with Entity Framework.
I have 2 tables : Theaters and Locality. Locality as a foreign key in Theaters.
My method :
public theater[] GetTheaters()
{
using (Entities context = new Entities())
{
return context.theater.ToArray();
}
}
I have to remove the "virtual" keyword from "public virtual locality locality { get; set; }" in my theater class. Otherwise, I get a CommunicationException.
But when I do that, I get my list of theaters but the locality is null...
How can I get the locality ?
Thanks
My model class ( I also have other entities) :
public partial class locality
{
public locality()
{
this.theater = new HashSet<theater>();
}
public int idLocality { get; set; }
public int npa { get; set; }
public string locality1 { get; set; }
public ICollection<theater> theater { get; set; }
}
public partial class theater
{
public theater()
{
this.session = new HashSet<session>();
}
public int idTheater { get; set; }
public string name { get; set; }
public string address { get; set; }
public int idLocality { get; set; }
public double latitude { get; set; }
public double longitude { get; set; }
public int seats { get; set; }
public string phone { get; set; }
public string email { get; set; }
public bool threeD { get; set; }
public locality locality { get; set; }
public ICollection<session> session { get; set; }
}
Here is the error that I get :
"Object graph for type 'locality' contains cycles and cannot be serialized if reference tracking is disabled.
EDIT :
The solution that I found :
In my locality class, I had a Collection of theaters.
I had to add "private to the setter like this :
" public ICollection theater { get; private set; }"
So it works, but I still have a problem, I can't access to the theaters from the locality entity anymore. (no more bi-directional)
If you want to force related entities to load, you can use the Include method to do so. By default, related entities are loaded Lazily.
Your example would be:
public theater[] GetTheaters()
{
using (Entities context = new Entities())
{
return context.theater.Include(t=>t.Locality).ToArray();
}
}
You can use eager loading or explicit loading. With eager loading you use the Include extension method:
return context.Theater.Include(t => t.Locality).ToArray();
You're missing the correct annotations to create the relationships. See the code below. (or create the relationships yourself if using the FluentAPI)
Look for the [Key] and [ForeignKey] annotations, as well as the virtual keyword.
public partial class locality
{
public locality()
{
//this.theater = new HashSet<theater>();
}
[Key]
public int idLocality { get; set; }
public int npa { get; set; }
public string locality1 { get; set; }
public virtual ICollection<theater> theaters { get; set; }
}
public partial class theater
{
public theater()
{
//this.session = new HashSet<session>();
}
[Key]
public int idTheater { get; set; }
public string name { get; set; }
public string address { get; set; }
public int idLocality { get; set; }
public double latitude { get; set; }
public double longitude { get; set; }
public int seats { get; set; }
public string phone { get; set; }
public string email { get; set; }
public bool threeD { get; set; }
[ForeignKey("idLocality")]
public virtual locality locality { get; set; }
//public ICollection<session> session { get; set; }
}