Entity Framework: unidirectional navigation with data annotation - entity-framework

I have to model 2 entities: Book and Label. Book class contains book information and the reference to Label class which contains a label text. I have therefore to realize a one way navigation from Book class to Label class because when I visualize a book entity I would like to read the Label value, but when I visualize a Label I don't want to have any information about Book.
I have found a lot of examples with Fluent API but I need to realize with Data Annotations. Any ideas?
public class Book
{
[Key]
public int id { get; set; }
public string Title { get; set; }
//What about label? How to navigate from Book to Label?
}
public class Label
{
[Key]
public int id { get; set; }
public string Name { get; set; }
}

You don't need any annotations, EntityFramework follows conventions, just add a property in the Book of type Label and the same for the other class, just like this:
public class Book
{
[Key]
public int id { get; set; }
public string Title { get; set; }
public Label Label {get;set;}
}
public class Label
{
[Key]
public int id { get; set; }
public string Name { get; set; }
public Book Book { get; set; }
}

Related

Scaffolding MVC Controller - how to indicate dataValueField and dataTextField?

One of the overload methods of SelectList (from the Microsoft.AspNetCore.Mvc.Rendering namespace) is defined as:
public SelectList(IEnumerable items, string dataValueField, string dataTextField);
When I scaffold an "MVC Controller with view, using Entity Framework" and I create my CRUD pages, I may see the following method inside of my Controller:
public IActionResult Create()
{
ViewData["Continent"] = new SelectList(_context.Continent, **"ContinentID", "ContinentID"**);
ViewData["Country"] = new SelectList(_context.Country, **"CountryID", "CountryName"**);
return View();
}
The field supplied to the dataTextField parameter is different between Continent/Country. How does MVC/EntityFramework decide which field to supply to dataTextField when scaffolding a Controller? Is there something in the individual models or in the DbContext that I am overlooking? I'd like for the dataTextField of Continent to be "ContinentName" so that I don't have to change it manually in the future when I need to delete and then re-scaffold the Controller.
Edit:
Here are the model definitions:
The Model of the Controller that I posted above:
using System;
using System.Collections.Generic;
namespace Project.Models
{
public partial class ProjectForm
{
public int ProjectFormID { get; set; }
public int ContinentID { get; set; }
public int CountryID { get; set; }
public virtual Continent ContinentNavigation { get; set; }
public virtual Country CountryNavigation { get; set; }
}
}
The one that displays the "CountryName" in the dataTextField the way that I want to see it:
namespace Project.Models
{
public partial class Country
{
public int CountryID { get; set; }
public string CountryName { get; set; }
public virtual ICollection<ProjectForm> ProjectForm { get; set; }
}
}
The one that displays the "ContinentID" in the dataTextField the way that I do NOT want to see it:
namespace Project.Models
{
public partial class Continent
{
public int ContinentID { get; set; }
public string ContinentName { get; set; }
public virtual ICollection<ProjectForm> ProjectForm { get; set; }
}
}
There is nothing obviously different to me in the model definitions unfortunately.
I stumbled across this post today (a bit late), but see it still hasn't been answered.
While I can't say why the scaffolding chose to use one field over another in your scenarios (unless you initially had your class/model written differently the last time you cleaned/built your project), I can say how to force it to use a specific column.
Add the DisplayColumn attribute to your class. You will need to rebuild before scaffolding again for the change to take.
namespace Project.Models
{
[DisplayColumn("ContinentName")]
public partial class Continent
{
public int ContinentID { get; set; }
public string ContinentName { get; set; }
public virtual ICollection<ProjectForm> ProjectForm { get; set; }
}
}

Entity Framework Code First existing database mapping relationship

I have an existing database which I would like to use Entity Framework Code First against in the most simple way possible. It is only a small database.
I have created simple POCO classes which mirror the database tables:
e.g.
public class Author
{
[Key]
public int AuthorID { get; set; }
public string AuthorName { get; set; }
public virtual ICollection<Books> Books { get; set; }
}
public class Books
{
[Key]
public int BookID { get; set; }
public string BookName { get; set; }
public int AuthorID { get; set; }
}
And a DbContext as follows:
public class Entities : DbContext
{
public Entities(string connString)
: base(connString)
{
}
public DbSet<Author> Authors { get; set; }
public DbSet<Books> Books { get; set; }
When I run my application, and select the first Author from my database, the AuthorID and AuthorName properties are populated correctly. However, the collection of Books is not populated. Instead there is an exception of type 'System.Data.EntityCommandExecutionException', and an inner exception of: 'Invalid column name 'Author_AuthorID'.
How can I establish correctly the link between Author and Books? (i.e. one to many, one Author can have many Books). I have created the Code First very simply - no migrations or auto-generation in any way, and would like to keep it as simple as this.
Many thanks for any help,
Martin
Fluent API Approach :
modelBuilder.Entity<Author>().HasMany(a => a.Books).WithRequired().HasForeignKey(b => b.AuthorID);
update :
with this fluent API you don't have to add property Author in Class Books
if you want to set Books to not required, you must set property AuthorID to int?
modelBuilder.Entity<Author>().HasMany(a => a.Books).HasForeignKey(b => b.AuthorID);
Books class :
public class Books
{
[Key]
public int BookID { get; set; }
public string BookName { get; set; }
public int? AuthorID { get; set; }
}
Add Author property (without it single AuthorID property not matter at context of relation with Authors table.):
public class Books
{
[Key]
public int BookID { get; set; }
public string BookName { get; set; }
public int AuthorID { get; set; }
//add this(attribute is not needed if you use EF6 or higher):
[ForeignKey("AuthorID")]
public virtual Author Author { get; set; }
}
Well, this is embarassing, I found an answer minutes after my post. I will post the answer, rather than deleting my question in case it helps anyone else:
public class Books
{
[Key]
public int BookID { get; set; }
public string BookName { get; set; }
[ForeignKey("Author")]
public int AuthorID { get; set; }
public Author Author { get; set; }
}

How do i create One-to-One mapping in EF 6 using Data Annotation approach

I am using EF 6.1.1.
I am unable to figure out how to create One-to-One relationship between two classes/tables with both entities have their owns PKs. I originally posted question link but could not get much help on it OR i am not able to get it. So, here i am putting my question in simple way.
Appreciate if someone can share thoughts on it.
My Requirement:
I would like create One-To-One relationship between Principle and Dependant with 'Id' from Principle class acts as Foreign Key in dependant class.
Principle Class
public class Student
{
public string FullName {get; set;}
}
Dependant Class
public class StudentReport
{
public string RollNumber { get; set; }
public string StudentType { get; set; }
}
Add PKs – EF requires this:
public class Student
{
public int Id { get; set; }
public string FullName { get; set; }
}
public class StudentReport
{
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
}
Note that EF 5 and later supports naming conventions: Id indicates a primary key. Alternately, it also supports the name of the class followed by "Id", so the above keys could have been StudentId for Student and StudentReportId for StudentReport, if you wished.
Add the foreign relation as a navigation property to at least one of the tables – in this case, you stated that StudentReport is the dependent, so let's add it to that one:
public class Student
{
public int Id { get; set; }
public string FullName { get; set; }
}
public class StudentReport
{
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
public Student Student { get; set; }
}
Again – by naming convention – EF determines that a single Student property on StudentReport indicates that this is a navigational property associated with a foreign key. (By defining only the Student property, but no foreign key property, you are indicating that you don't care what EF names the associated FK ... basically, you're indicating you'll always access the related Student via the property.)
If you did care about the name of the FK property, you could add it:
public class Student
{
public int Id { get; set; }
public string FullName { get; set; }
}
public class StudentReport
{
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
public int StudentId { get; set; }
public Student Student { get; set; }
}
Again – by naming convention – EF determines that StudentId is the FK associated with the Student property because it has the class name, "Student", followed by "Id".
All of this, so far, has been using conventions as defined in Entity Framework Code First Conventions, but Data Annotations are also an option, if you wish:
public class Student
{
[Key]
public int Id { get; set; }
public string FullName { get; set; }
}
public class StudentReport
{
[Key]
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
[ForeignKey("Student")]
public int StudentId { get; set; }
public Student Student { get; set; }
}
Doing this is actually a good idea, because it makes clearer your intent to other programmers that might not be aware of EF Conventions – but can easily infer them from simply looking at EF Data Annotations – and is still less cumbersome than Fluent API.
UPDATE
I just realized, I left this as a one-to-many, with enforcement of the one-to-one relationship being left to do in the code using this model. To enforce the one-to-one in the model, you could add a navigation property to the Student class going the other way:
public class Student
{
public int Id { get; set; }
public string FullName { get; set; }
public StudentReport StudentReport { get; set; }
}
public class StudentReport
{
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
public Student Student { get; set; }
}
However, that's going to break, because EF doesn't know which entity to insert first on an add. To indicate which is dependent, you have to specific that the dependent class' PK is the FK to the principal class (this enforces one-to-one because – in order for a Student/StudentReport pair to be associated – their Id properties must be the exact same value):
public class Student
{
public int Id { get; set; }
public string FullName { get; set; }
public StudentReport StudentReport { get; set; }
}
public class StudentReport
{
[ForeignKey("Student")]
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
public Student Student { get; set; }
}
or, using the full set of Data Annotations from earlier:
public class Student
{
[Key]
public int Id { get; set; }
public string FullName { get; set; }
public StudentReport StudentReport { get; set; }
}
public class StudentReport
{
[Key, ForeignKey("Student")]
public int Id { get; set; }
public string RollNumber { get; set; }
public string StudentType { get; set; }
public Student Student { get; set; }
}

Mapping nested classes via Entity Framework

I have class with this definition :
public class WebSiteContent
{
public Guid Id { get; set; }
public About About { get; set; }
public Tips Tips { get; set; }
public Images Images { get; set; }
}
where my About and Tips and Images are look like this :
public class About
{
public Guid Id { get; set; }
public string Text { get; set; }
public string Addres { get; set; }
public int PhoneNumber { get; set; }
public int Mobile { get; set; }
}
and Tips :
public class Tips
{
public Guid Guid { get; set; }
public string Content { get; set; }
}
and Images :
public class Images
{
public Guid Id { get; set; }
public string Background { get; set; }
public string Logo { get; set; }
public About About { get; set; }
}
here i just want to use about and Images and tips as a helper class to just create a property and don't want to have about,Images or tips table in database !
Entity framework needs Id to map all of above classes , how can I do that ?
here i just want to use about and Images and tips as a helper class to
just create a property and don't want to have about,Images or tips
table in database
So you are looking for complex type. Mark your About, Tips and Images classes with [ComplexType] attribute.
Entity framework needs Id to map all of above classes , how can I do
that ?
EF only needs Id for entities. If you map them as complex types you will not need to use any Id.
Btw. if you don't want to have those classes and their properties in database at all you can use [NotMapped] attribute instead.

Entityframework 4.3 codefirst using TPT and discriminator

I have these three models:
public class Equipment
{
public int ID { get; set; }
public string title { get; set; }
}
[Table("Vessels")]
public class Vessel:Equipment
{
public string Size { get; set; }
}
[Table("Tubes")]
public class Tube : Equipment
{
public string Pressure{ get; set; }
}
I want to show a list of Equipments with 2 columns title and type.
for example:
Title Type
------ -------
101-1 vessel
101-2 vessel
102-3 tube
I don't know how to make a discriminator column in Equipments to show the type of each equipments.
EDITED
If I have a discriminator in Equipment entity like:
public class Equipment
{
public int ID { get; set; }
public string title { get; set; }
public string type{ get; set; } //as discriminator
}
I can get the query in controller or repository like this:
var equipments=from e in db.Equipments
select e;
You cannot make discriminator column in terms of EF mapping - TPT inheritance doesn't support it because the discriminator is a subtable. You can try to use something like:
public abstract class Equipment
{
public int ID { get; set; }
public string title { get; set; }
[NotMapped]
public abstract string Type { get; }
}
and override Type property in subtypes to get the correct name. You will not be able to use that property in Linq-to-Entities queries because it is not mapped.