Home > OS >  Define one-to-many and one-to-one relationship on the same tables
Define one-to-many and one-to-one relationship on the same tables

Time:10-26

I am trying to create the following models in c# but am getting this error

System.InvalidOperationException: 'Unable to determine the relationship represented by navigation 'Activity.Token' of type 'Token2'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.'

Here are my 2 models

public class Token2
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public long Id { get; set; }

    [ForeignKey(nameof(LastActivity))]
    public long? LastActivityId { get; set; }

    public Activity? LastActivity { get; set; }

    public ICollection<Activity>? Activity { get; set; }
}

public partial class Activity
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public long Id { get; set; }
        public string Test { get; set; }

        [ForeignKey(nameof(Token2))]
        public long? TokenId { get; set; }

        public Token2? Token { get; set; }
    }

So the idea is that a Token has many activities related to it and I also want to keep that of the last activity acted on the Token.

And activity might be related to a Token or not, this is optional

How can i define this in EFCore?

CodePudding user response:

First Tip : Avoid using annotion Because in your case your entities Will be strongly depending on EF

Your Activity Entity :

public partial class Activity
{

    public long Id { get; set; }
    public string Test { get; set; }
    public DateTime Date { get; set; }
    public long? TokenId { get; set; }

    public Token? Token { get; set; }
}

the Token class

public class Token
{

    public long Id { get; set; }
    public Activity? LastActivity
    {
        get
        {
            return Activities .OrderByDescending(q => q.Date).FirstOrDefault();
        }
    }
    public ICollection<Activity>? Activities { get; set; }
}

And the configuration to add your on OnModelCreating Method

public class TokenConfiguration : IEntityTypeConfiguration<Token>
{
    public void Configure(EntityTypeBuilder<Token> builder)
    {
        builder.HasKey(a => a.Id);
        builder.HasMany(q => q.Activities).WithOne(q => q.Token).HasForeignKey(q => q.TokenId);
      
    }
}
public class ActivityConfiguration : IEntityTypeConfiguration<Activity2>
{
    public void Configure(EntityTypeBuilder<Activity2> builder)
    {
        builder.HasKey(a => a.Id);
       

    }
}

CodePudding user response:

ForeignKeyAttribute's documentation :

The annotation may be placed on the foreign key property and specify the associated navigation property name, or it may be placed on a navigation property and specify the associated foreign key name.

If you add ForeignKeyAttribute on the foreign key property Activity.TokenId, then you need specify the navigation property name Activity.Token (not the type Token2) like :

public partial class Activity
{
    ...
    
    [ForeignKey(nameof(Token))]
    public long? TokenId { get; set; }
    
    public Token2? Token { get; set; }
}

But the question example follow the navigation key/property name convention (the foreign key property name is foreign navigation property name with the suffix "Id"), then you can just remove the ForeignKeyAttribute and EF Core will automatically do the work.

  • Related