I am trying to represent a graph with typed edges in an entity-framework code-first model. I am having quite a difficulty understanding how to set up the relationships correctly. I am calling the nodes in my graph 'Items' and the edges 'Relationships' Here is what I have:
public class Item : Learnable
{
public Boolean IsBeginningItem { get; set; }
public virtual List<Relationship> RelationshipsLeft { get; set; }
public virtual List<Relationship> RelationshipsRight { get; set; }
}
-
public class Relationship : Learnable
{
public Boolean IsPrerequisiteRelationship { get; set; }
public virtual RelationshipType RelationshipType { get; set; }
public int ItemLeftID { get; set; }
[ForeignKey("ItemLeftID")]
public virtual Item ItemLeft { get; set; }
public int ItemRightID { get; set; }
[ForeignKey("ItemRightID")]
public virtual Item ItemRight { get; set; }
}
And here is what I am getting:
How can I get the RelationshipsRight property of Item to correspond to the ItemLeft property of Relationship AND the RelationshipsLeft property of Item to correspond to the ItemRight property of Relationship?
Oh... and I guess I should explain that this is supposed to be a directed graph that I can navigate bidirectionally. :)
You can use the [InverseProperty] attribute to bind the correct pairs of navigation properties together:
public class Relationship
{
//...
public int ItemLeftID { get; set; }
[ForeignKey("ItemLeftID"), InverseProperty("RelationshipsRight")]
public virtual Item ItemLeft { get; set; }
public int ItemRightID { get; set; }
[ForeignKey("ItemRightID"), InverseProperty("RelationshipsLeft")]
public virtual Item ItemRight { 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();
Two Tables One To Many
VehicleStatus {Id , LastVehicleStatusUpdateId}
VehicleStatusUpdated {Id, VehicleStatusId, IsResponse }
I need to make (one to zero or one) to last record in VehicleStatusUpdated ...
LastVehicleStatusUpdateId ==> Navigator To VehicleStatus
like This
How can i make it with Entity Framework Annotation ??!!
public class Vehicle : IEntity<int>
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public string Number { get; set; }
public virtual VehicleStatus VehicleStatus { get; set; }
}
public class VehicleStatus : IEntity<int>
{
[ForeignKey("Vehicle")]
public int Id { get; set; }
public virtual Vehicle Vehicle { get; set; }
public int? LastVehicleStatusUpdateId { get; set; }
[ForeignKey("LastVehicleStatusUpdateId")]
public virtual VehicleStatusUpdate LastVehicleStatusUpdate { get; set; }
public virtual List<VehicleStatusUpdate> VehicleStatusUpdates { get; set;
}
public class VehicleStatusUpdate : IEntity<int>
{
[ForeignKey("LastVehicleStatus")]
public int Id { get; set; }
public DateTime UpdatedTime { get; set; }
public bool IsResponse { get; set; }
public int VehicleStatusId { get; set; }
[ForeignKey("VehicleStatusId")]
public virtual VehicleStatus VehicleStatus { get; set; }
}
I Tried this i got =>
Unable to determine the relationship represented by navigation property 'VehicleStatus.LastVehicleStatusUpdate' of type 'VehicleStatusUpdate'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
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; }
}
For example we have profile and organisation. Both have articles.
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
}
public class Profile
{
public int Id { get; set; }
public string Email { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
public class Organisation
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
In this way Article should have two kinds of parent so it should have something like parent type to be able to access a parent when you select articles directly.
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
public int ParentId { get; set; }
public ArticleParentType Parent { get; set; }
}
Is it possible to map it using Entity Framework?
Is it a good idea to do it?
What is the best practice for storing this kind of data?
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
public int ParentId { get; set; }
public ArticleParentType Parent { get; set; }
}
Is it possible to map it using Entity Framework?
Is it a good idea to do it?
Possible yes but not a good idea. The underlying Database can't use a foreign key for Parentid. It would be slow.
What is the best practice for storing this kind of data?
A simple approach, with 2 Nullable parents and without CascadeOnDelete:
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
public virtual Profile Profile { get; set; }
public virtual Organisation Organisation { get; set; }
}
Alternatively you could use inheritance for Article, ie class OrganisationArticle : Article {}
Here are my models
public class Driver
{
public int Id { get; set; }
public String Name { get; set; }
public int VehicleId { get; set; }
public virtual Vehicle Vehicle { get; set; }
}
public class Vehicle
{
public int Id { get; set; }
public String Name { get; set; }
public virtual Driver Driver { get; set; }
public int VehicleGroupId { get; set; }
public virtual VehicleGroup Vehicles { get; set; }
}
I'm getting the following error on updating database:
Unable to determine the principal end of an association between the types 'AppName.Models.Vehicle' and 'AppName.Models.Driver'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
I wish to solve the issue using data annotations. I've tried putting foreign key attribute over Driver Navigation property in vehicle model. But no success. Any help is much appreciated.
To solve your problem you need to explicitly set the end of the association like this :
public class Vehicle
{
[Key, ForeignKey("Driver")]
public int Id { get; set; }
public String Name { get; set; }
public virtual Driver Driver { get; set; }
public int VehicleGroupId { get; set; }
public virtual VehicleGroup Vehicles { get; set; }
}
I think your model is inccorect because a driver can use many vehicles in real life ;)