Entity Framework 6 code first fluent API one to one relation with both ends required - entity-framework-6

I want to implement One to One relation with both ends required with the fluent API in Entity Framework 6 code first.
I have the principal class:
public class Student
{
public int Id{ get; set;}
public string Name{ get; set;}
public StudentProfile StudentProfile { get; set; }
}
and I have the dependent class:
public class StudentProfile
{
public int Id{ get; set;}
public string Description{ get; set;}
public Student Student { get; set; }
}
Additionally, I have the configuration for the relation one to one, in this case both ends ARE REQUIRED:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>()
.HasRequired(student => student.StudentProfile)
.WithRequiredPrincipal(profile => profile.Student);
base.OnModelCreating(modelBuilder);
}
After executing update-database, the resulting generated tables are:
The table StudentProfile columns:
The table Students columns:
On the Main program, I am able to save a Student with its profile:
UMLModel umlContext = new UMLModel();
//Studentprofile object
StudentProfile studentProfile = new StudentProfile();
studentProfile.Description = "Emily Profile Description";
//Student object
Student student = new Student();
student.Name = "Emily";
student.StudentProfile = studentProfile;
//Save Student and StudenProfile Objects
umlContext.Students.Add(student);
umlContext.SaveChanges();
Once executed the Main program,on the database,the StudentProfiles table is:
and the Students table is:
The problem becomes when I try to save one student WITHOUT its profile, the program allows to save it and it is supposed to not allow it:
UMLModel umlContext = new UMLModel();
Student student = new Student();
student.Name = "John";
umlContext.Students.Add(student);
umlContext.SaveChanges();
After executing the Main program, on the database, for table StudentProfiles now is:
and for table Students:
One way to prevent this is using data annotations, but I don't like this approach due the domain classes needs additional code:
public class Student
{
public int Id{ get; set;}
public string Name{ get; set;}
[Required]
public virtual StudentProfile StudentProfile { get; set; }
}
Questions:
Is it a bug from the fluent API?
Is there any way to solve this problem using the Fluent API without modifying
the domain classes?
Thanks in advance!

Perhaps have a look at the Stack Overflow answer here, which gives a nice explanation about 1:1 mappings in Entity Framework and some options for how you can map them so both ends are required: https://stackoverflow.com/a/30516623/2128831

Related

Entity Framework and Many-to-Many relationships, controlling the Intermediate table column names

I'm trying to wrap my head around a Many-to-Many relationship with Code-First mapping.
If I have an Album Class that can have many Genres (and vice-versa), I understand that I need to have an Intermediate table and Entity Framework will automatically do that for me. However, I would like a little more control over the Intermediate table, so I am creating one myself, the main reason is that I would like to be able to mark the row as deleted from the front-end and leave it in the database.
To do this for all my Classes I have created a BaseObject that they are Inherit from (I've removed many of the Annotations and other code to simplify this post):
public class BaseObject
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid Oid { get; set;
public DateTime DateCreated { get; set; }
public bool IsDeleted { get; set; }
public DateTime? DeletedDate { get; set; }
}
After that we have the Albums and Genres Classes:
public class Album : BaseObject
{
public string Name { get; set; }
public virtual List<AlbumsGenres> Albums { get; set; }
}
public class Genre : BaseObject
{
public string Name { get; set; }
public virtual List<AlbumsGenres> Genres { get; set; }
}
Finally the AlbumsGenres Intermediate Class:
public class AlbumsGenres : BaseObject
{
// Left blank because EF will create "Album_Oid" and "Genre_Oid" columns
// Tried the below code, but EF still created it's own Columns
/*
public Guid Album { get; set; }
public Guid Genre { get; set; }
*/
}
The questions that I have; Is there a way to tell EF to create Album_Oid with a different Column Name like Album?
I would accept an answer of "Just don't worry about it", if a brief explanation (or link) was provided.
You can control the intermediate table, Normally I use explicit mapping but the following works with CodeFirst:
In Album, you want a List<Genre> (not AlbumGenre)
In Genre, you want a List<Album>
In your context, add the following override for OnModelCreating:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Album>()
.HasMany(a => a.Genres)
.WithMany(g => g.Albums)
.Map(x =>
{
x.MapLeftKey("AlbumId");
x.MapRightKey("GenreId");
x.ToTable("AlbumGenres");
});
base.OnModelCreating(modelBuilder);
}

Entity Framework - Modeling multiple roles for same entity

I have a contact class
[Table("Contacts")]
public class Contact
{
public string Id { get; set; }
public string Name { get; set; }
}
I have two classes inheriting from Contact:
[Table("Employees")]
public class Employee : Contact
{
public decimal Salary { get; set; }
}
[Table("Suppliers")]
public class Supplier : Contact
{
public string TIN { get; set; }
}
I am using Entity Framework 6.3 as my ORM.
Can I model something where the same contact can be both Employee and
Supplier with the same unique Id.
Employee emp = new Employee();
emp.Id = "C1";
emp.Name = "Employees";
emp.Salary = 10000;
emp.TrackingState = TrackingState.Added;
Supplier sup = new Supplier();
sup.Id = "C1";
sup.Name = "Employees";
sup.TIN = "ABC";
sup.TrackingState = TrackingState.Added;
When I do:
context.Employee.Add(emp);
context.Supplier.Add(sup);
context.Save();
Obviously, it will not allow me to add the record.
I get an error:
"Violation of PRIMARY KEY constraint 'PK_dbo.Contacts'. Cannot insert duplicate key in object 'dbo.Contacts'. The duplicate key value is (C1).\r\nThe statement has been terminated."
Can I make the Supplier also share the same Id as that of employee and
enable insert / update of employee and supplier?
Thanks
I assume you are not doing any specific inheritance mapping which by default will map this as Table per Hierarchy (TPH) inheritance. With this mapping you get a single Db table that contains the aggregate of all the fields in the base type and the dependent types with a discriminator field to know which type the row should be materialized. This allows for doing a query where you ask for a type.
With TPH each row can only be a single type, so you can not have the same row be both an Employee and Supplier.
There is another type of mapping you can do called Table Per Type (TPT) which will create a table for each type, so in your case 3, one for the shared fields, and one for each dependent type. This should allow for what you are asking about. (YMMV)
However, it seems to be that Employee and Supplier would be used in much different domains so I would suggest that you create your Contact table and relate it to both your employee and supplier.
[Table("Contacts")]
public class Contact
{
public string Id { get; set; }
public string Name { get; set; }
}
[Table("Employees")]
public class Employee
{
public string Id { get; set; }
public string ContactId { get; set; }
public decimal Salary { get; set; }
public Contact Contact { get; set; }
}
[Table("Suppliers")]
public class Supplier
{
public string Id { get; set; }
public string ContactId { get; set; }
public string TIN { get; set; }
public Contact Contact { get; set; }
}
Now you can query for an employee:
db.Employees.Include(e => e.Contact).First();
Or for a Supplier:
db.Employees.Include(e => e.Contact).First();
Which might be cleaner than the inheritence query you would need:
db.Contacts.OfType<Employee>().First();
In both the Has A modeling I show above and the Is A Modeling with TPT you are getting three tables. You just have the FK in what I show rather than the same ID in 3 tables with TPT.
There is also Table Per Class you can look at, which is similar to TPT but you don't get a table for the abstract/parent class, rather you get table for each dependent type with all the fields in it. I don't think this is what you want because it would have duplicate data, however, it does mean less joins.

Remove primary key in entity framework table field in mvc4

I have created a model in the name of Sample with an Id and DocumentId property.In this I don't mention primary key for Id property.But it forms the primary key when I created the Sample as table in entity framework.I want to remove the primary key for Id. What do I have to do. Please help me. I am very new to mvc4.
public class Sample
{
[Required,DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
[Required]
public int DocumentId { get; set; }
}
public override void Up()
{
CreateTable(
"dbo.Samples",
c => new
{
Id = c.Int(nullable: false, identity: false),
DocumentId = c.Int(nullable: false),
})
.PrimaryKey(t => t.Id);
}
I am putting this here as I don't think it will show up very well in comments :)
In the case of a user having many roles (and each role possibly being played by many users), you would have three tables linked to 2 classes. The tables would be a Users table with a unique UserId column and the rest of the user details. Another table would be Roles with a unique RoleId and the rest of the role information and a joining table that would have the id of the user and the id of the role he plays (this table could have a unique id of itself). If the user has 2 roles, they would have 2 records in the joining table, one for each of the roles. The classes would look something like this:
public class User{
public long UserId {get;set;}
public ICollection<Role> roles{get;set;}
//Other properties of the user name, DOb,etc.
}
public class Role{
public long RoleId{get;set;}
public ICollection<User> Users{get;set;}
//other properties of Role
}
This is a many to many relationship. Of course you could also have it as a one to many relationship if the role can be played by one user. In that case you don't need the joining table and you can just add a UserId column to the Role table and instead of a collection of users, the role would have a single property of type user (not really needed unless you want to navigate back from role to user).
Try adding the NotMapped attribute in your Id.
public class Sample
{
[Key]
public int SampleId {get;set;}
[Required,DatabaseGenerated(DatabaseGeneratedOption.None)]
[NotMapped]
public int Id { get; set; }
[Required]
public int DocumentId { get; set; }
}
EDIT:
I added a key attribute to specify your primary key.
You can also try this, which I think is better:
public class Sample
{
public int SampleId {get;set;}
public virtual ICollection<Document> Documents {get;set;}
}
public class Document
{
public int DocumentId {get;set;}
public int SampleId {get;set;}
public virtual Sample Sample {get;set;}
}
virtual keyword is for lazy loading.
Open the entity diagram (.edmx) file and find which ever property in that particular table is the primary key. Right click on it and select "properties". In the properties window see where it says StoreGeneratedPattern - Identity? Change that to none and save the diagram. It will regenerate the .cs model files by itself
Fluent API suppresses the Data Annotations in Entity framework. Data Annotation for Primary is [Key] and ID is by default Primary key with identity.
In that scenario, Delete(if it's there) Data Annotation of ID i:e;[KEY] and use Fluent API in your context class. In below example, my primary key is "CustomerName" due to Fluent. Example:
public class Customer
{
public int CustomerName { get; set; }
public int ID { get; set; }
[Required]
public string ProductID { get; set; }
}
In Context Class:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>().HasKey(s => s.CustomerName);
}

Code first relationships with entity framework, fluent API

I have a legacy table I need to connect my app to. I am using a code-first, POCO model. I have the following classes:
public class Equipment
{
[Key]
public string EquipmentId { get; set; }
public string OriginatorId { get; set; }
public virtual Employee Employee { get; set; }
}
public class Employee
{
[Key]
[Column("employee_id")]
public string EmployeeId { get; set; }
public string EmployeeName { get; set; }
[ForeignKey("OriginatorEmployeeId")]
public virtual Equipment Equipment { get; set; }
}
I need to map EmployeeId in the Employee class to to OriginatorEmployeeId in the Equipment class.
Also, the legacy table is represented by the Employee class. The table is actually named employee (lower case) and the EmployeeId column is named "employee_id". I want to keep naming of my classes and properties consistent with the rest of the app, hence Employee and EmployeeId.
Here is what I have tried using fluent API:
modelBuilder.Entity<Employee>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("employee");
});
modelBuilder.Entity<Equipment>()
.HasOptional<Employee>(u => u.Employee)
.WithOptionalDependent(c => c.Equipment).Map(p => p.MapKey("OriginatorEmployeeId"));
I am probably mixing things I don't need to. The error I am getting right now is:
Multiplicity is not valid in Role 'Equipment_Employee_Source' in relationship 'Equipment_Employee'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.
Any help is appreciated.
Can an employee record be associated to more than one equipment record? If they can then your Employee POCO should contain a collection property representing a one-to-many relationship between Employee and Equipment.
public virtual ICollection<Equipment> Equipments {get;set;}
You configuration should then be adjusted accordingly to show this relationship:
modelBuilder.Entity<Employee>()
.HasMany<Equipment>(u => u.Equipments)
.WithRequired(c => c.Employee).HasForeignKey(p => p.OriginatorId);
It also looks like you will need to setup a configuration for your column name mappings as well. Therefore, I would recommend that you create a separate configuration file for each of your POCOs to make it easier to manage the configurations, then just add those configurations to the modelbuilder.Configurations collection in your OnModelCreating event of your DBContext
public class EmployeeConfiguration : EntityTypeConfiguration<Employee>
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelbuilder.Configurations.Add(new EmployeeConfiguration());
}

Entity Framework 4.1 Code First: Single column foreign-key to multiple entities

I've been trying to create model in EF 4.1 to represent a database schema with a single table and column holding foreign keys from two other tables, but have had little luck with both annotations and the fluent API. A sample model is shown here:
public class User
{
...
public virtual ExtendedAttribute ExtendedAttributes { get; set; }
}
public class Account
{
...
public virtual ExtendedAttribute ExtendedAttributes { get; set; }
}
public class ExtendedAttribute
{
public Guid Id {get; set;}
public Guid ItemId {get; set;} // both Account.Id and User.Id stored here
public string Value { get; set; }
}
Currently the configuration for these entities looks something like this for both User and Account modelBuilders:
this.HasOptional(u => u.ExtendedAttributes).WithRequired();
Any thoughts on how to do achieve? Many thanks.
It is even not possible with the database itself and EF will not put any abstraction for that. You must have separate column and navigation property for each entity.

Resources