I'm using dot net core 2.0, I have 2 classes, with a many to many relation defined.
Each class has a corresponding definition like so:
public virtual ICollection<INSERT_CLASS_HERE> MyObjects { get; set; }
I'm finding that I can retrieve a particular object for name or Id from the DB Context, yet the Collection that makes the many relationship, is coming up null.
I feel like it's something simple, but its been some time since I last touched dotnet... let alone dotnet core.
Related
I have a table for a spot. This spot can have different categories. For example: restaurant, hotel, park.
Each individual category has additional and different details.
My questions now:
Is it possible to create a column (FK) in the spot table that is independent of the category?
I mean when I create a new spot with the category Resteraunt and the next one is with the category park.
If I now select a spot that I get the correct data from the respective spot category
And if possible, how can I write that in C# EF Core Models?
Or is this not possible and i have to take another way?
Thanks in advance
Database Design for Example:
No, you can't have an FK column that is independent of the table it's referencing (the manifestations of your category). What you're looking for is inheritance. EF Core 5 currently supports two types of inheritance - Table Per Hierarcy (TPH) and Table Per Type. Either can work for your purposes.
First, you implement your entity Classe in an inheritance hierarchy to be mapped to the database with the derived classes representing the "category" of Spot:
public abstract class Spot
{
public Guid Id { get; set; }
// common spot properties here
// (i.e. props shared by different types of spots like address)
}
public class Restaurant : Spot
{
// restaurant specific properties here
}
public class Park : Spot
{
// park specific properties here
}
Then you map the entities in one of two ways - either to a single table (TPH) which will use a discriminator column to type each record in the DB (would be considered your category) and each property for the derived types would also be included but only populated for the specific type of record (i.e. Park properties will be null when the record in the DB represents a Restaurant and vice versa). Faster query performance with this method but all type-specific columns must be nullable and this implementation violates 3NF.
TPH is the default inheritance implementation but you can configure how it handles the discriminator like any other property (name, datatype) and specify the values to use for each derived type:
modelBuilder.Entity<Spot>()
.HasDescriminator("Category") // name it what you want
.HasValue<Restaurant>("R") // value for restaurants
.HasValue<Park>("P") // value for parks
;
In TPT each type in the inheritance hierarchy is mapped to its own table which contains their specific properties. The tables for the derived types use shared primary keys to reference their corresponding Spot record. Query performance can be slower and while it doesn't violate 3NF, its possible for manual data manipulation operations to mess things up (e.g. a Park and a Restaurant can reference the same Spot record).
For this configuration, merely map each type in the entity hierarchy to its own table:
modelBulider.Entity<Restaurant>().ToTable("Restaurant");
modelBuilder.Entity<Park>().ToTable("Park");
For both implementations, you can implement the DbSet properties normally:
public DbSet<Spot> Spots { get; set; }
public DbSet<Restaurant> Restaurants { get; set; }
public DbSet<Park> Parks { get; set; }
You can get specific types of Spots from Spots by using .OfType<T>()
var parks = dbContext.Spots.OfType<Park>();
So you do not need the Restaurants or Parks DbSet<T>s if you include the Spots DbSet<T>. Alternatively, Spots is optional if you include DbSet<T>s for the derived types.
I encourage you to model your entities both ways to see how EF models the DB and choose which you prefer.
https://learn.microsoft.com/en-us/ef/core/modeling/inheritance
I'm using Entity Framework - Database First in my project. My model has a view with only one VARCHAR column:
CREATE VIEW MyView
AS
SELECT 'Eris' Eris
FROM MyTable
By default, this view gets mapped to its own entity with just one property:
public virtual DbSet<MyView> MyViews { get; set; }
How can I change this so that the view gets mapped to a List of strings instead:
public virtual List<string> Eris { get; set; }
Unfortunately EF does not support mapping collections of value types. If you really want to implement this scenario then you might want to look into other ORM frameworks that have this feature like NHibernate.
If that's not an option and you have to stick to EF then you're forced to create an entity with one property like you mentioned in your question.
The entity model represents one element in the table.
When you retrieve data from the table, you will get a list of entity model objects.
On my own projects I use RavenDB. At work I use SQL Server and Entity Framework (code first).
So designing domain entities is a challenge, as I really enjoy RavenDB's ability to create an application-centric, DDD style application, that isn't tied at all to a database implementation.
At the moment I'm trying to persist an entity that has a collection of GUIDs that reference other entities in the system. For example (not the actual class, but the same concept):
public class Thing
{
public Thing()
{
this.VisibleSectionIds = new Collection<Guid>();
}
public Guid Id { get; set; }
public string Name { get; set; }
public ICollection<Guid> VisibleSectionIds { get; set; }
}
Using RavenDB, I can persist this in a few lines of code with no need to redesign the database. I can even make my collection of ids read-only.
Can people suggest ways that I could do a similar thing in EF without introducing mapping properties to other entities (this would break my DDD approach and possibly introduce N+1 issues). Can I use EF to convert my collection of GUIDs to a text datatype in the database and convert it back again?
I have the following code in my context, and no explicit table-class mapping, yet my database keeps getting created (by my DropCreateDatabaseIfModelChanges initializer) with an EmployeeStatus table, not EmployeeStatuses. Is there a known issue with this, or am I going insane or what?
public DbSet<Department> Departments { get; set; }
public DbSet<EmployeeStatus> EmployeeStatuses { get; set; }
All my other tables are named exactly after their DbSet names, as I expect.
Entity Framework uses its pluralization service to infer database table names based on
the class names in the model—Destination becomes Destinations, Person becomes
People, etc. By convention, Code First will do its best to pluralize the class name and use the results as the name of the table. However, it might not be the same as your
table naming conventions.
You can use the Table Data Annotation to ensure that Code First maps your class to
the correct table name.
I have the following
[DataContractAttribute]
public class Animal
{
[Key]
[XmlElement(ElementName = "Id")]
[DataMember()]
public Guid Id
{
get;
set;
}
[XmlElement(ElementName = "AnimalType")]
[DataMember()]
public List<AnimalType> AnimalType
{
get;
set;
}
}
And i map it through the code first approach with EF to tables
modelBuilder.Entity<Animal>().ToTable("Animal");
As you see I have not performed some complex mapping, but the List of AnimalType enumerations did not get mapped automatically to any columns/tables in the DB. Do i need to add some extra code to the model builder to control the mapping of an enumeration list ?
As of EF CTP5, enums are not supported yet. The team announced that they are going to fully support enums in their next RTM version which is targeted to be released on the first quarter of 2011.
I know for the longest time, enums weren't supported by EF, though I don't know if that is still the case or not.
Either way, I think there is a general problem with having EF handle a list of a type other than another entity. What is the primary key? What is the value? Should it try to store the data in one column or create a separate table and create a foreign key constraint? These are questions that will likely need to be answered before your model can be converted into a database schema.