There is a Cargo class/table which has identity CargoID
There is a ContainerIn class/table which containes CargoID
Every Cargo could have 1 or 0 corresponding container entries.
I am trying to create navigation properties such that.
Cargo.ContainerIn--->should give me associated ContainerIn entry
ContainerIn.Cargo--->should give me associated Cargo entry
Cargo Class:
public class Cargo
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CargoID { get; set; }//SerialNo
[Required]
public DateTime DateOfPassage { get; set; }
public string CompanyUserName { get; set; }
public virtual ContainerIn ContainerIn { get; set; }
}
ContainerIn Subclass:
public class ContainerIn
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ContainerInID { get; set; }
public int CargoID { get; set; }
public virtual Cargo Cargo { get; set; }
public int LoadStatus { get; set; }
}
I have also tried adding public int ContainerInID { get; set; } inCargo` class.
I am still getting :
`Unable to determine the principal end of an association between the types 'PisMark3.Models.Cargo.ContainerIn' and
'PisMark3.Models.Cargo.Cargo'.
The principal end of this association must be explicitly configured
using either the relationship fluent API or data annotations.`
EDIT:
I have added OnModelCreating in ApplicationDbContext class.
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<PisMark3.Models.Cargo.Cargo>()
.HasOptional(s => s.ContainerIn)
.WithRequired(ad => ad.Cargo);
}
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
// Database.SetInitializer<ApplicationDbContext>(new DropCreateDatabaseIfModelChanges<ApplicationDbContext>());
}
....
Now I am getting:
you're pretty close. I think you want the following:
public class Cargo
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CargoID { get; set; }//SerialNo
[Required]
public DateTime DateOfPassage { get; set; }
public string CompanyUserName { get; set; }
public int ContainerInId { get; set; } //need to define a foreign key. This is happening by naming convention in this case as with your `ContainerIn.CargoId` foreign key
public virtual ContainerIn ContainerIn { get; set; }
}
public class ContainerIn
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ContainerInID { get; set; }
public int CargoID { get; set; }
public virtual Cargo Cargo { get; set; }
public int LoadStatus { get; set; }
}
Note this is a circular reference which should probably be avoided if possible however there are certainly some valid use cases. Just thought I'd give a shout out to that.
If you don't want to abide by naming conventions, you can use the ForeignKey data annotation as outlined here
unable to determine the principal end of an association between the
types 'PisMark3.Models.Cargo.ContainerIn' and
'PisMark3.Models.Cargo.Cargo'. The principal end of this association
must be explicitly configured using either the relationship fluent API
or data annotations
This is telling you to define your relationship, because it can not understand the relationship.
What you are looking for is
One-to-Zero-or-One relationship here is the link
This is your model,
public class Cargo
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CargoID { get; set; }//SerialNo
[Required]
public DateTime DateOfPassage { get; set; }
public string CompanyUserName { get; set; }
public virtual ContainerIn CompanyUserNameContainIn { get; set; }
}
public class ContainerIn
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ContainerInID { get; set; }
public int LoadStatus { get; set; }
public int CargoID { get; set; }
public virtual Cargo Cargo { get; set; }
}
This is your flent api code,
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Cargo>()
.HasOptional(s => s.CompanyUserNameContainIn)
.WithRequired(ad => ad.Cargo);
}
This tells entityframework that it has optional companyusername in cargo model and required model cargo in ContainerIn
You can read more in detail in the link I provided, it has nice example of student and address.
EDIT:
As you want to use identityDBContext you can modify your code as below
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public virtual DbSet<Cargo> Cargo { get; set; }
public virtual DbSet<ContainerIn> ContainerIn { get; set; }
public ApplicationDbContext()
: base("DefaultConnection")
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Cargo>()
.HasOptional(s => s.CompanyUserNameContainIn)
.WithRequired(ad => ad.Cargo);
modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id);
modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId });
}
}
Related
I'm trying to learn to use Code First. On Picture 1 you can see the EER Model I want to become from my Code First application.
Now I have tried to get the same result from my application. Below you can see the EER Model I've managed to become from my app (with Reverse Engineering in MySQL Workbench).
As you can see I have a problem with creating a one to zero or one relationship between tables 'Properties' and 'Grounds'.
I have an abstract EntityBase class
public abstract class EntityBase
{
public abstract int Id { get; set; }
}
Also a GenericRepository class which inherits the EntityBase class
public class GenericRepository<T> : IRepository<T> where T : EntityBase
A MapDBContext class which inherits the DbContext class. Inside this class you can see that the OnModelCreating method is 'Override'. Inside of that method I have tried to configure the relationship between the 'Properties' and 'Grounds' tables.
public class MapDBContext : DbContext
{
public virtual DbSet<Agreements> Agreements { get; set; }
public virtual DbSet<BuyersRenters> BuyersRenters { get; set; }
public virtual DbSet<Properties> Properties { get; set; }
public virtual DbSet<Grounds> Grounds { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Grounds>().HasOptional(s => s.Properties).WithRequired(lu => lu.Grounds);
base.OnModelCreating(modelBuilder);
}
public MapDBContext(string connectionString) : base(connectionString)
{
}
}
Below are the two Code First classes of the 'Properties' and 'Grounds' tables (NOTE: Properties class is abstract):
[Table("eigendommen")]
public abstract class Properties : EntityBase
{
public override int Id { get; set; }
[Column("gemeente")]
[Required]
public string Town { get; set; }
[Column("straat")]
[Required]
public string Street { get; set; }
public virtual List<Agreements> Agreements { get; set; }
public virtual Grounds Grounds { get; set; }
}
[Table("gronden")]
public class Grounds : Properties
{
[Key]
public override int Id { get; set; }
[Column("opp")]
public double? Surface { get; set; }
[Column("type")]
[EnumDataType(typeof(TypeNames))]
[Required]
public TypeNames Types { get; set; }
public virtual Properties Properties { get; set; }
}
Can somebody help me with what I am doing wrong? I've been searching for hours, tried with the 'required' attribute, with the '?' to make it nullable and with the 'ForeignKey' attribute. But all of these solutions give either errors or a similar table to the one I have now.
To define one to one and zero with code first c#
if you want have one or zero Address for the student.
You can follow the code below
public class Student
{
public Student() { }
public int StudentId { get; set; }
public string StudentName { get; set; }
public virtual StudentAddress StudentAddress { get; set; }
}
public class StudentAddress
{
[ForeignKey("Student")]
public int StudentAddressId { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public int Zipcode { get; set; }
public string State { get; set; }
public string Country { get; set; }
public virtual Student Student { get; set; }
}
you must define OnModelCreating in the DbContext and then relation between student and studentaddress.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Configure the primary key for the StudentAddresses
modelBuilder.Entity<StudentAddress>()
.HasKey(t => t.StudentAddressId);
// Map one-to-zero or one relationship
modelBuilder.Entity<StudentAddress>()
.HasRequired(t => t.Student)
.WithOptional(t => t.StudentAddress);
}
I am rather new to EntityFramework's Code First approach and I'm getting the following error when I try to to create a reusable complex type that references an entity type.
Models:
class Bank
{
public int Code { get; set; }
public string Name { get; set; }
}
class BankAccount
{
public Bank Bank { get; set; }
public int BankId { get; set; }
public int Agency { get; set; }
public int Account { get; set; }
}
class Person
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime BirthDate { get; set; }
public BankAccount BankAccount { get; set; }
}
DbContext:
class DemoContext : DbContext
{
public DbSet<Bank> Banks { get; set; }
public DbSet<Person> People { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Bank>().HasKey(b => b.Code);
modelBuilder.ComplexType<BankAccount>();
}
}
When I try to add a Migration I get the following error:
One or more validation errors were detected during model generation:
ComplexTypeProblem.EF.Bank: Name: Each type name in a schema must be unique. Type name 'Bank' is already defined.
ComplexTypeProblem.EF.Bank: : EntityType 'Bank' has no key defined. Define the key for this EntityType.
Banks: EntityType: EntitySet 'Banks' is based on type 'Bank' that has no keys defined.
Is there any caveat to implement this kind of relationship where a ComplexType has a navigation property to an EntityType?
Thanks
You can't have a ComplexType containing an EntityType. Only the other way around.
ComplexTypes are simply properties for an entity, and they should work on your code just like normal fields.
Are you trying to set up a 1 -> many mapping for the Bank / BankAccounts? If so, I would recommend the following:
public partial class Bank
{
public Bank()
{
BankAccounts = new List<BankAccount>();
}
public int Code { get; set;}
public string Name { get; set;}
public virtual ICollection<BankAccount> BankAccounts { get; set;}
}
public partial class BankAccount
{
public int BankId { get; set;}
public int Agency { get; set;}
public int Account { get; set;}
public virtual Bank Bank { get; set;}
}
And change the OnModelCreating method as follows:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Bank>().HasKey(b => b.Code);
modelBuilder.Entity<Bank>().HasMany(m => m.BankAccounts).WithRequired(r => r.Bank).HasForeignKey(f => f.BankId).WillCascadeOnDelete(false);
}
I'm using Entity Framework 6 with a Code-First approach, and I want two entities to be put in the same table. What am I doing wrong?
[Table("Review")]
public class Review
{
public int Id { get; set; }
public PictureInfo PictureInfo { get; set; }
public int PictureInfoId { get; set; }
}
[Table("Review")]
public class PictureInfo
{
[Key, ForeignKey("Review")]
public int ReviewId { get; set; }
public Review Review { get; set; }
}
The error I get:
The entity types 'PictureInfo' and 'Review' cannot share table 'Review' because they are not in the same type hierarchy or do not have a valid one to one foreign key relationship with matching primary keys between them.
What am I doing wrong?
Seems like the problem was that the relationship was interpreted as one-to-0..1 instead of one-to-one.
The foreign key int PictureInfoId on the Review end was unneeded/ignored, so its non-nullability did not make the Review end of the relationship required. Removing this unneeded key and adding the [Required] attribute to the PictureInfo navigational property solved it.
Here's the corrected Review class.
[Table("Review")]
public class Review
{
public int Id { get; set; }
[Required]
public PictureInfo PictureInfo { get; set; }
}
I've managed to achieve what you wanted with fluent api. Fluent api offers much richer options for configuration than data-annotations. I've changed a bit your entity classes:
public class Review
{
public int Id { get; set; }
public PictureInfo PictureInfo { get; set; }
}
PictureInfoId property is not necessary as foreign key relationship will be done on primary keys of both entities.
public class PictureInfo
{
public int Id { get; set; }
public Review Review { get; set; }
}
Because Review and PictureInfo will be mapped to the same table they need to share the same primary key column so for PictureInfo and Review this column should have the same name. If you would like to keep in PictureInfo primary key property named ReviewId you can do this but you would need then to map its name to "Id". Finaly the DbContext:
public class MyDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Review>().HasKey( e => e.Id );
modelBuilder.Entity<Review>()
.HasRequired(e => e.PictureInfo)
.WithRequiredDependent(e => e.Review);
modelBuilder.Entity<Review>().Map(m => m.ToTable("Review"));
modelBuilder.Entity<PictureInfo>().Map(m => m.ToTable("Review"));
modelBuilder.Entity<PictureInfo>().HasKey(e => e.Id);
base.OnModelCreating(modelBuilder);
}
public DbSet<Review> Reviews { get; set; }
public DbSet<PictureInfo> PictureInfos { get; set; }
}
OnModelCreating holds fluent api mapping definition. All you have to do is to define primary keys on both entities with the same name, bind those 2 entities with 1-1 relation and then map them to the same table.
The other way to resolve this issue is to create a view with just the desired fields. Then map the entity to the view.
(These tests and errors were written against EF 6.1.3)
First Attempt
[Table("Review")]
public class Review
{
[Key]
public int Id { get; set; }
public PictureInfo PictureInfo { get; set; }
}
[Table("Review")]
public class PictureInfo
{
[Key]
public int Id { get; set; }
public Review Review { get; set; }
}
With the above entities I received this error:
Unable to determine the principal end of an association between the
types. The principal end of this association must be explicitly
configured using either the relationship fluent API or data
annotations.
Second Attempt
[Table("Review")]
public class Review
{
[Key]
public int Id { get; set; }
[Required]
public PictureInfo PictureInfo { get; set; }
}
[Table("Review")]
public class PictureInfo
{
[Key]
public int Id { get; set; }
[Required]
public Review Review { get; set; }
}
The entity types 'Review' and 'PictureInfo' cannot share table
'Review' because they are not in the same type hierarchy or do not
have a valid one to one foreign key relationship with matching primary
keys between them.
Third Attempt
[Table("Review")]
public class Review
{
[Key]
public int Id { get; set; }
[Required, ForeignKey("Id")]
public PictureInfo PictureInfo { get; set; }
}
[Table("Review")]
public class PictureInfo
{
[Key]
public int Id { get; set; }
[Required, ForeignKey("Id")]
public Review Review { get; set; }
}
Unable to determine the principal end of an association between the
types. The principal end of this association must be explicitly
configured using either the relationship fluent API or data
annotations.
Working Code
[Table("Review")]
public class Review
{
[Key, ForeignKey("PictureInfo")]
public int Id { get; set; }
public PictureInfo PictureInfo { get; set; }
}
[Table("Review")]
public class PictureInfo
{
[Key, ForeignKey("Review")]
public int Id { get; set; }
public Review Review { get; set; }
}
using System.Linq;
using System.Data.Entity;
namespace Sample
{
class Program
{
static void Main(string[] args)
{
using (var context = new EmployeeDBContext())
{
var result = context.Set<Employee>().Include(x => x.Department).ToArray();
}
}
}
public class EmployeeDBContext : DbContext
{
public EmployeeDBContext() : base("EmployeeDB") { }
public DbSet<Employee> Employee { get; set; }
public DbSet<Department> Department { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Department>().ToTable("Departments").HasKey(x => x.DepartmentId);
modelBuilder.Entity<Employee>().ToTable("Employees").HasKey(x => x.Id);
//ForeignKey mapping
modelBuilder.Entity<Employee>().HasRequired(x => x.Department).WithMany().HasForeignKey(x => x.DepartmentId);
base.OnModelCreating(modelBuilder);
}
}
//Domain Entity
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Department Department { get; set; }
public int DepartmentId { get; set; }
}
//Domain Entity
public class Department
{
public int DepartmentId { get; set; }
public string DepartmentName { get; set; }
}
}
I wanted to add a note here for people who get this error, but did not mean to have both entities point to the same table...
Make sure you did not accidentally place an incorrect Table name in your "Table" attribute.
The error is caused because the definition of the table is duplicated in the directive of Table "PictureInfo". You need only edit that's directive.
[Table("Review")]
public class Review
{
...
}
[Table("Review")]
public class PictureInfo
{
...
}
for
[Table("Review")]
public class Review
{
...
}
[Table("PictureInfo")]
public class PictureInfo
{
...
}
I just started using Code first approach for creating databases. I have following 3 tables :
public class TagDatabase
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int TagID { get; set; }
public string TagName { get; set; }
public string Description { get; set; }
public int Count { get; set; }
[ForeignKey("TagTypes")]
public virtual int TagTypeID { get; set; }
public virtual ICollection<TagTypesDb> TagTypes { get; set; }
[ForeignKey("Users")]
public virtual int CreatedBy { get; set; }
public virtual UsersDb Users { get; set; }
}
public class TagTypesDb
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int TagTypeID { get; set; }
public string TagTypeName { get; set; }
}
public class UsersDb
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserID { get; set; }
public string UserName { get; set; }
}
Here TagDatabse and User and TagType have 1 to 1 replationship. The fluent API code which i used for this is :
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<TagDatabase>()
.HasOptional(a => a.TagTypes)
.WithMany()
.HasForeignKey(u => u.TagTypeID);
modelBuilder.Entity<TagDatabase>()
.HasRequired(a => a.Users)
.WithMany()
.HasForeignKey(u => u.CreatedBy);
}
Now my issue is whenever i am trying to insert data in TagDatabase i got this exception :
TagDatabase_TagTypes: : Multiplicity conflicts with the referential constraint in Role 'TagDatabase_TagTypes_Target' in relationship 'TagDatabase_TagTypes'. Because all of the properties in the Dependent Role are non-nullable, multiplicity of the Principal Role must be '1'.
The TagTypeId property is allowed nulls .so i used HasOptional() in OnModelCreating method.
Cananybody please tell me how to solve this issue and what i am missing here ?
You should make the foreign key property nullable if the corresponding relationship is optional.
public class TagDatabase
{
//sniff...
[ForeignKey("TagTypes")]
public virtual int? TagTypeID { get; set; } //Since TagTypes is optional, this should be nullable
public virtual ICollection<TagTypesDb> TagTypes { get; set; }
//sniff...
}
I have the below DbContext, Model and Controller (database first). These are referents for two tables (operador and operador2), that complement each other. I mapped these models (table "operador") with (some table) successfuly, but the mapping reference for (table "operador") and (table "operador2") not works fine. I think I have less anything for this it work correctly. (Below the code and a image when the controller has executed.) I need a relationship between and through properties "OpedradorId" and "Operador2Id". Somebody can help me?
/**** DbContext ****/
public class OperadorContext : DbContext
{
public OperadorContext() : base("name=CnxEasyLabWeb") { }
public DbSet<OperadorModel> DbOperador { get; set; }
public DbSet<OpCadastros1Model> DbCadastro { get; set; }
public DbSet<OpCadastros2Model> DbCadastro2 { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<OperadorModel>().HasKey(o => o.OperadorId);
modelBuilder.Entity<OpCadastros1Model>().HasKey(c => c.OperadorId);
modelBuilder.Entity<OpCadastros1Model>()
.HasRequired(c => c.Operador)
.WithRequiredPrincipal(o => o.OpCadastros1);
modelBuilder.Entity<OpCadastros1Model>()
.HasRequired(c => c.OpCadastros2)
.WithRequiredDependent(d => d.OpCadastro1);
modelBuilder.Entity<OperadorModel>().ToTable("operador", "public");
modelBuilder.Entity<OpCadastros1Model>().ToTable("operador", "public");
modelBuilder.Entity<OpCadastros2Model>().ToTable("operador2", "public");
}
}
/**** Models ****/
public class OpCadastros1Model //: OpGeralModel
{
[Key, Column("id")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int OperadorId { get; set; }
public virtual OperadorModel Operador { get; set; }
public virtual OpCadastros2Model OpCadastros2 { get; set; }
}
public class OpCadastros2Model
{
[Key, Column("operador_id")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int OperadorId { get; set; }
public virtual OpCadastros1Model OpCadastro1 { get; set; }
}
public class OperadorModel
{
[Key, Column("id")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int OperadorId { get; set; }
public virtual OpCadastros1Model OpCadastros1 { get; set; }
[Column("nome")]
[Required]
public string Login { get; set; }
}
/**** Controller ****/
[HttpPost]
//[Authorize]
[ValidateAntiForgeryToken]
public ContentResult SalvarCadastros(OpCadastros1Model model)
{
if (ModelState.IsValid)
{
#region Update
if (model.OperadorId > 0)
{
var update = _db.DbCadastro.Single(op => op.OperadorId == model.OperadorId);
_db.Entry(update).CurrentValues.SetValues(model);
_db.Entry(update).State = EntityState.Modified;
}
#endregion
#region New
else
{
_db.DbCadastro.Add(model);
}
#endregion
_db.SaveChanges();
}
else
{ ... }
...
}
Complementary, I receive this error:
The property 'Operador2Id' is part of the object's key information and
can not be modified.
You must have a class that is the primary and other that is the detail.
On the primary, declare everything normally:
public class Operador
{
[Key, Column("id")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int OperadorId { get; set; }
public virtual OpCadastros1Model OpCadastros1 { get; set; }
}
On the secondary, do this:
public class OpCadastros1Model
{
[Key, Column("id"), ForeignKey("Operador")]
public int OperadorId { get; set; }
[Required]
public Operador Operador { get; set; }
}
This means that the primary has an optional relationship with the detail and the detail has a required relationship with the primary and gets its primary key from it.