6

Have the class below, and try to look for records in the database returns error. Using C #, MVC 4, Entity Framework 4 and SQL Server 2012 database.

Error

Unable to determine the principal end of an association between the types 'FlexApp.Models.Model.Usuario' and 'FlexApp.Models.Model.Usuario'. 

The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.

Class

public class Usuario
{
    [Key]
    public int UsuarioID { get; set; }
    public string Nome { get; set; }
    public int UsuCad { get; set; }        
    public int UsuAlt { get; set; }

    [ForeignKey("UsuCad")]
    public virtual Usuario UsuarioCad { get; set; }
    [ForeignKey("UsuAlt")]
    public virtual Usuario UsuarioAlt { get; set; }
}

DataBase FK

alter table USUARIO add constraint USUARIO_fk01 foreign KEY(UsuCad) REFERENCES USUARIO(UsuarioID);
alter table USUARIO add constraint USUARIO_fk02 foreign KEY(UsuAlt) REFERENCES USUARIO(UsuarioID);
Julius Depulla
  • 1,493
  • 1
  • 12
  • 27
Tiedt Tech
  • 719
  • 15
  • 46

3 Answers3

4

reply

After searching a lot, I found a tip about using InverseProperty Then the code looks like this. This property ForeignKey It is to mount the link and property InverseProperty for to inform that the field depends on this other camp, reversing the foreign key.

Thanks for the help

public class Usuario
{
    [Key]
    public int UsuarioID { get; set; }
    public string Nome { get; set; }
    public int UsuCad { get; set; }        
    public int UsuAlt { get; set; }

    [ForeignKey("UsuCad")]
    [InverseProperty("UsuarioID")]
    public virtual Usuario UsuarioCad { get; set; }
    [ForeignKey("UsuAlt")]
    [InverseProperty("UsuarioID")]
    public virtual Usuario UsuarioAlt { get; set; }
}
Tiedt Tech
  • 719
  • 15
  • 46
3

I am not 100% sure what kind of db schema you are trying to achieve here. My assumption is that you want to have foreign key to the same table. In your comment, you said you want a one to one relation ship. Technically this is not possible. Because when you try to insert the first record, You need to provide a value for your foreign key column. The value should be an Id of an existing record. Wait... We don't have any records yet !

Since 1-1 is not really practical here, You should be doing a one to zero/one relationship. That means your foreign key column should be nullable so that you can insert your first record with NULL value in your foreign key column.

I am having a little hard time understanding your model & property names. So i am going to use a general class/table which everyone can understand, but with your specific requirement ( Self reference foreign key)

I am not using data annotations, I am using Fluent API

The silly business requirement/assumption is that :

  • One Person may or may not have a Parent
  • One Person may or may not have a Kid

So our entity class will look like this

public class Person
{
    public int Id { set; get; }
    public string Name { set; get; }
    public virtual Person Parent { set; get; }
    public virtual Person Kid { set; get; }    
}

Now to use fluent API to control the relationships, We need to go to our DBContext class and override the OnModelCreating method

public class MyDbContext : DbContext
{
    public MyDbContext() : base("MyConnectionStringName") { }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {    
        modelBuilder.Entity<Person>().HasKey(d => d.Id)
            .HasOptional(m => m.Kid).WithOptionalPrincipal(d=>d.Parent);

        base.OnModelCreating(modelBuilder);
    }   

    public DbSet<Person> Persons { set; get; }
}

This will create the table with 3 Columns, ID, Name and Parent_Id (NULLABLE, Foreign Key relationship to ID of same table)

I can insert data like this

var db = new MyDbContext();

var myMom = new Person {Name = "Indira"};
var me = new Person {Name = "Shyju", Parent = myMom};
var myDaughter = new Person { Name = "Gauri", Parent = me};

db.Persons.Add(myMom);
db.Persons.Add(me);
db.Persons.Add(myDaughter);

db.SaveChanges();

And you will have your data with ParentId column having a foreign key to the ID column of the same table.

enter image description here

Shyju
  • 214,206
  • 104
  • 411
  • 497
-1

The error is because the class name Usuario is exactly the same as the in the property public virtual Usuario UsuarioAlt { get; set; }

You cannot use the same type as a navigation property. The issue here is the navigation properties are wrong. Think of SQL database table, Can the same unique primary key be a foreign key in the same table? You need your foreign key to come from another table.

The navigation properties are what Entity Framework use to determine the entity relational model between your POCOs and hence your database tables.

You want a different class for the relation. If you have a second class with that name, use namespace aliasing, so the runtime can know the difference between the two class, now it is like a class referencing itself .

You should write your model as below

public class Usuario
{
    [Key]
    public int UsuarioID { get; set; }
    public string Name { get; set; }
    public int UsuCad { get; set; }        
    public int UsuAlt { get; set; }
    public virtual SomeSecondClass SomeSecondClass { get; set; }
    public virtual SomeThirdClass SomeThirdClass { get; set; }
}

public class SomeSecondClass 
{
   public int SomeSecondClassID { get; set;}
   // More properties
}

public class SomeThirdClass 
{
   public int SomeThirdClassID { get; set;}
   // More properties
}
Julius Depulla
  • 1,493
  • 1
  • 12
  • 27
  • but this way I will have to duplicate classes? – Tiedt Tech Nov 25 '15 at 23:04
  • No, you will not have duplicate classes. I have expanded on the code hope it helps.This is Code First Approach. Using EF conventions. Read this blog. http://tinyurl.com/p24ytvt – Julius Depulla Nov 25 '15 at 23:15
  • You can have a property with the same name as the class in EF, if you have a self-referencing table. – SWeko Nov 25 '15 at 23:17
  • @SWeko You cannot use the same type as a navigation property. Issue here is the navigation properties are wrong. Think of SQL database table, Can the same unique primary key be a foreign key in the same table? You need your foreign key to come from another table. – Julius Depulla Nov 25 '15 at 23:20
  • @SWeko The navigation properties are what Entity Framework use to determine the entity relational model between your POCOs and hence your database tables – Julius Depulla Nov 25 '15 at 23:25
  • If I use only one reference to `Usuario`, it works. If you use two, gives the error – Tiedt Tech Nov 25 '15 at 23:26
  • If you do not want any entity relationship to any other classes or POCOs, you can delete those two properties with the virtual keyword – Julius Depulla Nov 25 '15 at 23:28
  • @coderealm - no, it can be self referencing - think parent / child relationship. I'm actually looking at the exact same case (only configured with fluid api, not annotations) – SWeko Nov 26 '15 at 09:08
  • @Sweko Very clear distinction though parent / child relationship rather than Parent/Parent or Child/Child Relationship which is self referencing – Julius Depulla Nov 26 '15 at 20:22
  • @coderealm - the reference is actually Person/Person, and one of those persons is the parent, and one of the persons is the child. Take a look at Shyju's answer. – SWeko Nov 26 '15 at 22:01