Using entity framework 6 and mvc 5, assuming I have the following models:
class Employee
{
public int EmployeeID { get; set; }
public String Name { get; set; }
public Department Department { get; set; }
}
class Department
{
public int DepartmentID { get; set; }
public String DepartmentName { get; set; }
public int FloorNumber { get; set; }
}
In my DbContext class where the DbSet goes, do I do DbSet<Employee> only or do I also have to do DbSet<Department>? Right now I'm only doing DbSet<Employee> because the way I understand it, the main model is Employee which has a complex type Department inside, so theoretically if Employee loads then Department should load passively (load as in create a table)?
Currently, I have Department as a virtual field for lazy loading because when I try to access it without the virtual attribute I get a null pointer exception.
Also, my model is a little more complex than this with multiple complex objects, do each of these need their own DbSet?
Thank you
According to the documentation (emphasis is mine):
Type Discovery
<snip>
In the following example, there is only one DbSet property defined on
the SchoolEntities class (Departments). Code First uses this property
to discover and pull in any referenced types.
However, if you ever wish to manipulate lists of Employees independent from your Department, then you should include it.
Related
I have two entities Employee, Branch
public class Branch
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public int ManagerId { get; set; }
public Employee Manager { get; set; }
public List<Employee> Employees { get; set; }
public List<Department> Departments { get; set; }
}
public class Employee
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int ManagerId { get; set; }
public Employee Manager { get; set; }
public int DepartmentId { get; set; }
public Department Department { get; set; }
public int BranchId { get; set; }
public Branch Branch { get; set; }
}
each branch has many departments, each department has many employees, each employee belong to one department and one branch
the database scheme should look like this :
Branch : Id , Name , ManagerId
Department : Id , Name , ManagerId
Employee : Id , Name , DepartmentId , BranchId, ManagerId #(department manager)
I want to have OneToOne relationship for Branch with Employee (Manager), and OneToMany relationship for Branch with Employee (Employees Of Branch)
right now when I try to add migrations, it fails with
Unable to determine the relationship represented by navigation
property 'Branch.Manager' of type 'Employee'
I understand the issue, but not able to solve it.
This design is too de-normalized which leads to a risk of invalid associations, and more explicit mapping needed for relationships.
For instance, if a Branch has a Manager, and a collection of employees, then an employee can get their manager via the Branch. I.e.
employee.Branch.Manager
The issue with having Manager on both Employee and Branch is there is no way to ensure that employee.Manager and employee.Branch.Manager are always pointing at the same person. (where they should always be the same person)
A Department may have a manager as well, but this would be expected to be a higher level manager where each branch has a manager that reports to a department manager.
EF will sometimes get confused trying to work out associations between entities by convention if you don't specify the FK relationship between the FK property and navigation property. From memory, EF convention uses the Property type, not the property name as the default expected key name.
So for instance given a property
public virtual Employee Manager { get; set; }
You might expect EF to work out to expect a FK to be "ManagerId" but instead it would attempt to use "EmployeeId" by default based on the type Employee not the property name. This is why you would need to explicitly point it at "ManagerId" as the FK using the ForeignKey attribute or better, using .Map(x => x.MapKey("ManagerId")) or EF Core Shadow Properties to avoid declaring FK properties in your entities alongside the navigation properties.
What is the difference between foreign key reference using Id vs object.
For example:
FK relation using Id
class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string PhoneNumber { get; set; }
public int CategoryId { get; set; }
}
vs
FK relation using object
class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string PhoneNumber { get; set; }
public Category Category { get; set; }
}
I have noticed from database that by using Id property the column essentially becomes non-null field.
Is that the only difference?
I think we can't query multiple tables at once i.e.querying related data?
When should I choose to use either options?
In your first example you're not adding a relationship, just an integer property named CategoryId.
In your second example, Entity Framework will create an integer column named "Category_ID", but you will be not be able to see this property in your model, so I like to explicitly add it my self and be able to use it along with the navigation property.
class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string PhoneNumber { get; set; }
[ForeignKey("Category")]
public int CategoryId { get; set; }
public Category Category{get;set;}
}
This way you can also control the data type of CategoryId, so you could make it optional (nullable)
public int? CategoryId { get; set; }
*The foreign key data annotation is not needed, unless you have property or navigation property names that do not follow the naming convention for foreign key property names (Bardr), it doesn't harm to explicitly declare it either for clarity purposes
This implies that you're creating a 1 to many relationship (1-*) with products and categories, so in your Category class you would be adding a collection navigation property for products
class Category
{
public int Id{ get; set;}
public string Name{ get; set; }
...
public ICollection<Product> Products{get; set;}
}
Basically it depends on your use case and what type of loading related data you choose. Whether you use Id or object reference or full relationship on both sides (Id and object) it depends on your overall application architecture. If you wil go and use full or object reference everywhere, you will (probably) end up with a mess, and you won't know whether you should query for some entities using their repository or if it'll be okay to include them to some other query. I highly recommend you to take a look at this book, especially chapter 19 (Aggregates) and 21 (Repositories). There you have an in-depth explanation of what I meant and much more. (This does not only apply to applications built in DDD way)
I'm a bit confused by conflicting examples of one-to-many model relationships using EF that I'm seeing online.
One video I watched setup a relationship between tables like so:
public class CustomerType
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public int CustomerTypeId { get; set; }
public CustomerType CustomerType { get; set; }
}
So a Customer can only have one CustomerType, but a CustomerType can be used by many Customers. This code works fine, I can fetch a Customer's CustomerType with LINQ using Include.
Now I'm looking at another resource showing the same kind of relationship:
public partial class Standard
{
public int StandardId { get; set; }
public string StandardName { get; set; }
public virtual ICollection<Teacher> Teachers { get; set; }
}
public partial class Teacher
{
public int TeacherId { get; set; }
public string TeacherName { get; set; }
public Nullable<int> StandardId { get; set; }
public virtual Standard Standard { get; set; }
}
This looks almost the same, except:
In this example, the Standard class (equivalent to my CustomerType) has a navigation property back to a collection of Teachers, which my first example does not have. Is this just convenient to have if I want to get a list of all teachers for a given standard, or is it necessary to properly set up the relationship?
The properties in the second example are marked virtual and the first are not -- it seems that best practice is to make nav properties virtual, but is there a reason you wouldn't want to do that?
If it matters, I'm using MVC5 and EF6 and I just want to know if one example is right and one is wrong, or just two styles of getting to the same place.
Thanks!
The navigational properties are to make queries easier for the programmer. Your examples are basically the same with the difference that in Standard you can access Teachers through query while in CustomerType you can not access Customers with this CustomerType because you do not have it as a navigational property. Nevertheless, you can always include List<Customer> Customers in Customer Type.
Also it is better to add virtual to your navigational property for the sake of lazy loading.
MSDN
It depends on your needs, if you will never have to get the navigation property and just need a foreign key for sake of data integrity then you can simply add an integer and mark it as a foreign key. ex: instead of having a CustomerType instance, you can simply have a CustomerTypeId and that is it.
As for the virtual keyword, you can add it if you want to have a lazy loading enabled in your DBContext, cause EF generates proxy classes that inherits from your model classes and it overrides the virtual properties to add the needed logic to lazy load the navigation properties.
If you have a lazy loading disabled, then no need to mark any property as virtual
Say I have an abstract Person Table, and derived tables, Student and Teacher, Admin etc. Person has a enum property PersonType with values for each derived class, and a virtual collection Events.
Now when Entity Framework creates the Events table, it creates a column for each class derived from Person, eg. Student_Id, Teacher_Id, Admin_Id etc.
If I have a dozen derived classes, then that's a dozen extra columns, only 1 of which is ever in use.
How do I tell Entity Framework to instead refer to the PersonType property in conjunction with the Id instead of creating all these unnecessary columns?
So it has simple solution with DataAnnotations, if i understood you correctly.
[Column("TableID")]
I'm going to give you a working example from a project of mine. So i have an abstract Class which has called Trip. Cruise and Hotel classes are derived from Trip class. I need to Store Comments on a single table and as you have concerned i dont need CruiseID nor HotelID on Comments table so i named TripID with Column Annotation and entity framework will create table magically if we annotated well
public class Comment
{
public int CommentID { get; set; }
[Column("TripID")]
[ForeignKey("Trip")]
public int TripID { get; set; }
public virtual Trip Trip { get; set; }
public string Text { get; set; }
}
public class CruiseComment : Comment
{
[Column("TripID")]
[ForeignKey("Cruise")]
public int CruiseID { get; set; }
public virtual Cruise Cruise { get; set; }
}
public class HotelComment : Comment
{
[Column("TripID")]
[ForeignKey("Cruise")]
public int HotelID { get; set; }
public virtual Hotel Hotel { get; set; }
}
It's not necessary to use ForeignKey annotation. It's needed when you have different namings.
I'm building a fairly simple MVC project and still getting my head around where to use navigation properties and foreign keys with code first.
This is the main model class:
public class GroceryItem
{
public int ID { get; set; }
public string Name { get; set; }
public GroceryCategory Category { get; set; }
public QualityProfile Quality { get; set; }
public GroceryStore BestStore { get; set; }
public double BestPrice { get; set; }
public double LastSeenPrice { get; set; }
//Navigation Properties
public virtual ICollection<GroceryItem> SimilarItems { get; set; }
}
and these are the relating classes:
public class GroceryStore
{
public int ID { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public Uri Website { get; set; }
}
public class QualityProfile
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
/// <summary>
/// Rank out of 1-10, 10 being the best
/// </summary>
public byte Ranking { get; set; }
}
public class GroceryCategory
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
Which brings me to my question, is the navigation property of SimilarItems I have in the GroceryItem class sufficient to represent a list of multiple grocery items or does this not work as it is referring to itself?
Additionally...do the Category, Quality and BestStore properties require ID properties to represent a foreign key inside of the GroceryItem class (e.g. CategoryID), or is the way I have this represented OK?
----EDIT----
--Refactored Code--
I've re-factored my model based on the suggestions below, which I think better accommodates the suggestions you've made (yes a 2nd time), realised my model was a little flawed and extracted out the price component into a separate purchases Model.
public class GroceryItem
{
public int ID { get; set; }
public string Name { get; set; }
[ForeignKey("Category")]
public int CategoryID { get; set; }
[ForeignKey("Quality")]
public int QualityID { get; set; }
//Navigation Properties
public virtual QualityProfile Quality { get; set; }
public virtual GroceryCategory Category { get; set; }
}
However the last thing I'm uncertain about which is on topic to this post, is if I have a collection as a part of the model (one that does not reference itself like in the first example), can I just represent that with a navigation property or does an extra step need to be taken?
Ie. If I was to allow multiple different categories on a GroceryItem, instead of looking like this:
[ForeignKey("Category")]
public int CategoryID { get; set; }
public virtual GroceryCategory Category { get; set; }
it would look like this:
public virtual ICollection<GroceryCategory> Categories { get; set; }
The best answer to your question(s) is, "It depends". Navigation properties are one way of informing Entity Framework that there's a relationship between entities. By convention, if you have a navigation property such as:
public Category Category { get; set; }
Entity Framework will create a column on the table named in the form of [RelatedPropertyName]_[RelatedPK]. Given your classes, the property above would cause a column named Category_ID. There's nothing more you need to do make it work. The relationship will automatically be handled by EF.
However, doing it this way, you won't have access to this foreign key property. It's not exposed in the public API of your entity. Often, especially when selecting related items from a select list and similar such scenarios, this becomes problematic, as you must store the selected value some place else, usually a property on a view model, and then use this to query the related thing from the database before setting it on the entity it belongs to and finally saving the entity. Whereas, with an actual foreign key property, you can simply post directly back to this and Entity Framework will automatically wire up the related entity. As a result, I tend to always follow the following pattern with my navigation properties:
public int FooId { get; set; }
public virtual Foo Foo { get; set; }
In most scenarios, Entity Framework will automatically connect those two, such that FooId will hold the foreign key relationship for the Foo navigation property. However, occasionally, EF will trip up and try to create the implicit foreign key behind the scenes, still, but you can correct that behavior by explicitly telling EF that this is the foreign key:
[ForeignKey("Foo")]
public int FooId { get; set; }
Roughly the same applies with collection navigation properties. EF will see this as an indication that there's a one-to-many relationship in play and add the implicit foreign key on the opposite entity. Given your collection:
public virtual ICollection<GroceryItem> SimilarItems { get; set; }
The opposite entity is actually the same entity, which presents an interesting use case. Typically, EF would handle this by assuming there's a one-to-many relationship. You'd end up with a column named GroceryItem_ID on your dbo.GroceryItems table. Here, though, you would not only have no access to the foreign key directly, but you also have no public API for accessing the parent GroceryItem either. That may not be a problem, but it's something to be aware of. The only way you'd be able to manage the relationship is through the collection on the parent, not through a child item in that collection.
However, since this is self-referential and you have not specify a foreign key or instance navigation property, all EF will see is a collection on both sides of the relationship, so my guess is that you'll actually end up with an M2M with an intermediary table. I can't test that theory out myself at the moment, and I haven't tried this particular scenario myself previously.
To create a true one-to-many, you would need to create another navigation property similar to:
public virtual GroceryItem ParentGroceryItem { get; set; }
And, even, then, I don't think EF will get the point without a little Fluent configuration:
HasMany(m => m.SimilarItems).WithOptional(m => m.ParentGroceryItem);
You could also use WithRequired in other scenarios instead of WithOptional, which would obviously make the relationship a required one, but since this is self-referential, it's impossible to have it required, because there will have to be at least one root node with no parent.