I have a little problem with Entity Framework when trying to model the real life
problem.
I have 2 entity like this :
public class Person
{
public int Id { get; set; }
public ICollection<Task> Tasks{ get; set; }
}
public class Task
{
public int Id { get; set; }
public Person Assignee{ get; set; }
public Person Assigner{ get; set; }
}
but if I want to use Entity framework,it forces me to change my model like this that it is different from real life !!
public class Person
{
public int Id { get; set; }
public ICollection<Task> AssigneesTasks{ get; set; }
public ICollection<Task> AssignerTasks{ get; set; }
}
(i just have single one-to-many relation in fact)
what is the solution to keep my model according to real life model?
Well you might want to know what tasks a person has assigned to them, and what tasks they have assigned to others. If you don't want both Navigation properties you don't need them in EF. But you do need to tell EF which relationship the Navigation Property is for. EG:
public class Person
{
public int Id { get; set; }
[InverseProperty("Assignee")]
public ICollection<Task> Tasks { get; set; }
}
public class Task
{
public int Id { get; set; }
public Person Assignee { get; set; }
public Person Assigner { 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 Got This Issue:
I Have the Application User Class Like This
public class ApplicationUser : IdentityUser
{
public ROLES Role { get; set; }
public int? CompanyId { get; set; }
public int? AreaId { get; set; }
public string Document { get; set; }
public bool Enable { get; set; }
[ForeignKey("CompanyId")]
public virtual Company Company { get; set; }
[ForeignKey("AreaId")]
public virtual Area Area { get; set; }
public virtual ICollection Measures { get; set; }
}
And I Got this another Model:
public class Area
{
public int AreaId { get; set; }
public string AreaName { get; set; }
public int CompanyId { get; set; }
public string UserId { get; set; }
[ForeignKey("CompanyId")]
public virtual Company Company { get; set; }
[Key, ForeignKey("UserId")]
public ApplicationUser ApplicationUser { get; set; }
}
And when i try to:
add-migration
the PM Console throws:
Unable to determine the principal end of an association between the types 'x.Models.ApplicationUser' and 'x.Models.Area'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
I have been trying all day but I can't find a way to tell the Entity Framework to recognize the relation.
Any ideas?
Thanks for reading
Add Attribute for AreaId in Area class
[Key]
public int AreaId { get; set; }
and if you want 1-1 relationship for ApplicationUser and Area update your code like
[Unique]
[ForeignKey("UserId")]
public ApplicationUser ApplicationUser { get; set; }
The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations
This Post give me the Answer I Need!!!
It's pretty hard to find...
So I let you the post here...
Thanks for all of your help!
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 {}
I'm currently building an SPA with Web API and knockout etc. So far i worte my own simple datacontext and it worked pretty well.
The I bumped in to breeze and thought it might be worth a try. especially I hoped to get a simpler approach on navigation between the entities...
to load a entities or a single entity with breeze worked fine. Working with navigation properties seems not to work. The navigation property is always empty, even though it's a one to many relationship.
Here is my model (simplified):
public class WorkdayHours
{
public int Id { get; set; }
public bool IsWorkDay { get; set; }
...
public Byte WeekDay { get; set; }
}
public class Service
{
public int Id { get; set; }
public string DisplayName { get; set; }
public virtual ICollection<WorkdayHours> BookableDays { get; set; }
}
public class Employee
{
public int Id { get; set; }
public string DisplayName { get; set; }
public virtual ICollection<WorkdayHours> BookableDays { get; set; }
}
public class Shop
{
public int Id { get; set; }
public string DisplayName { get; set; }
public virtual ICollection<WorkdayHours> BookableDays { get; set; }
}
Then I fetch the entity service ind my SPA as follow:
var query = EntityQuery
.from('Services')
.where('id', 'eq', serviceId)
.expand('BookableDays');
As when teh query is executed I get as result the requested service entity with all the data except the bookableDay property is always an empty array.
When I check the Json answer I see that also the workdayHours are transmitted and breeze even calls my defined ctors for this entities. However they are not linked to the bookableDays property itself.
When checking the genrated DB model, EF generated foreignkeys for service, employee and shop in workdayHours as expected.
Is breeze not capable with having several optional foreignkeys?
Suggestion and ideas highly apprechiated.
Breeze is dependent on Foreign Keys. I had a similar problem. This should solve it:
EF was generating the ForeignKeys for me too and the related Entites where still empty. As far as i know breeze needs the explicit Annotation/Configuration of ForeignKey Fields.
public class Mvl
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long MvlId{ get; set; }
public DateTime CreatedAt { get; set; }
[InverseProperty("Mvl")]
public ICollection<MvlOP> MvlOps { get; set; }
public DateTime? ReleasedAt { get; set; }
public DateTime? LockedAt { get; set; }
public DateTime? ClosedAt { get; set; }
//[ConcurrencyCheck]
//public int? RowVersion { get; set; }
[Timestamp]
public byte[] TimeStamp { get; set; }
}
public class MvlOP
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long MvlOpId { get; set; }
public long MvlId { get; set; }
[ForeignKey("MvlId")]
public Mvl Mvl { get; set; }
...
}
I have an EF code-first model with a table having several one-to-many relationships with other tables:
public class Note
{
[Key]
public Guid Id { get; set; }
public string NoteText { get; set; }
public string Author { get; set; }
public DateTime? CreationDate { get; set; }
}
public class Foo
{
public Foo()
{
Notes = new HashSet<Note>();
}
[Key]
public Guid Id { get; set; }
public virtual ICollection<Note> Notes { get; set; }
// other properties ommited...
}
public class Bar
{
public Bar()
{
Notes = new HashSet<Note>();
}
[Key]
public Guid Id { get; set; }
public virtual ICollection<Note> Notes { get; set; }
// other properties ommited...
}
As you can see, both Foo and Bar have their own list of Notes, but a Note belongs to either a Foo or a Bar.
When scaffolding the migration, EF creates a foreign key for Foo and Bar in the Notes table, which I think is not correct. I would like, instead, that a link table is created between Foo and Notes and another one between Bar and Notes.
Is there a way to automatically do this? Or do I have to manually create these classes in my code-first implementation?
This has already been answered in this other post!
But to save you a little googling, you are getting a one-to-many association, which is correct. you want a many-to-many relationship in your code, so what you will need to do is :
in your Notes class:
public class Note
{
[Key]
public Guid Id { get; set; }
public string NoteText { get; set; }
public string Author { get; set; }
public DateTime? CreationDate { get; set; }
public DateTime? CreationDate { get; set; }
public virtual ICollection<Foo> Foos { get; set; }
public virtual ICollection<Bar> Bars { get; set; }
}
Hope this helps