The entity type 'Access' requires a primary key to be defined. If you intended to use a keyless entity type call 'HasNoKey()'
Asked Answered
S

4

14

i have this ValueObject :

public class Access : ValueObject<Access>
{
    public string ControllName { get;  set; }
    public string ActionName { get;  set; }

    private Access()
    {

    }
    public Access(string controllerName, string actionName)
    {
        ControllName = controllerName;
        ActionName = actionName;
    }

    protected override IEnumerable<object> GetEqualityComponents()
    {
        yield return ControllName;
        yield return ActionName;
    }
}

and this is my ValueObject<Access> :

 public abstract class ValueObject<T>
    where T : ValueObject<T>
{
    protected abstract IEnumerable<object> GetEqualityComponents();

    public override bool Equals(object obj)
    {
        var valueObject = obj as T;

        if (ReferenceEquals(valueObject, null))
            return false;

        return IsEquals(valueObject);
    }

    private bool IsEquals(ValueObject<T> other)
    {
        return GetEqualityComponents().SequenceEqual(other.GetEqualityComponents());
    }

    public override int GetHashCode()
    {
        return GetEqualityComponents()
            .Aggregate(1, (current, obj) => current * 23 + (obj?.GetHashCode() ?? 0));
    }

    public static bool operator ==(ValueObject<T> a, ValueObject<T> b)
    {
        if (ReferenceEquals(a, null) && ReferenceEquals(b, null))
            return true;

        if (ReferenceEquals(a, null) || ReferenceEquals(b, null))
            return false;

        return a.Equals(b);
    }

    public static bool operator !=(ValueObject<T> a, ValueObject<T> b)
    {
        return !(a == b);
    }
}

and this is my DBContext :

 public class StoreAdminPanelGetwayContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlServer(@"Server=.; initial catalog=StoreAdminPanelGetway;integrated security=true");

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyConfigurationsFromAssembly(typeof(Role).Assembly);
    }
    public DbSet<Role> Roles { get; set; }
    public DbSet<AccessLevel> AccessLevels { get; set; }

}

this is my entity :

  public class AccessLevel : Entity
{
    public int RoleId { get;  set; }
    public Access Access { get;  set; }
    public Role Role { get; set; }
}

but when i need to add-migration initial databse it show me this error :

The entity type 'Access' requires a primary key to be defined. If you intended to use a keyless entity type call 'HasNoKey()'.

but Access is value object and it can not have an id . how can i solve this problem ???

Saffren answered 9/3, 2020 at 12:44 Comment(0)
E
24

EF Core has the concept of Owned Entity Types, which can be used to implement DDD value types.

In OnModelCreating you would do the following:

modelBuilder.Entity<AccessLevel>().OwnsOne(x => x.Access);

This would store Access objects in the same database table as AccessLevel objects, and therefore requires no primary key.

Encratis answered 9/3, 2020 at 12:49 Comment(2)
You could also do this for single values builder.Property(c => c.Access) .HasConversion(c => c.Value, c => new Access(c.action, c.controller));Ravine
I have this same problem, but I'm already setting up the value object as an owned entity. Yet I still get the error that it "requires a primary key to be defined". Any ideas on what might cause this?Maturate
L
18

If you are scaffolding a .net controller using a model and you get this error

The entity type 'Access' requires a primary key to be defined. If you intended to use a keyless entity type call 'HasNoKey()'

it is because the model you are using in your command does not have and key property.

By convention, a property named Id or Id will be configured as the primary key of an entity.

internal class Car
{
    public string Id { get; set; } //this is the key

    public string Make { get; set; }
    public string Model { get; set; }
}

internal class Truck
{
    public string TruckId { get; set; } //this is the key

    public string Make { get; set; }
    public string Model { get; set; }
}

When your primary key does not follow that convention you can use the [Key] to indicate what property your entity key is:

public class GameStats {
    [Key]
    public String playerName {set; get;}
    public int gamesWon {set; get;}
}

If your entity does not have keys you can use [KeyLess]

[Keyless]
public class BlogPostsCount
{
    public string BlogName { get; set; }
    public int PostCount { get; set; }
}

Taken from

Luau answered 8/3, 2021 at 1:19 Comment(2)
Just a note: This is applicable starting from EF Core 5.0 and above.Cherimoya
This "modelBuilder.Entity<BlogPostsCount>().HasNoKey();" should be added in the database context too.Gittern
B
0

If you want to save your value object in a different table, you can use a shadow property to define an ID that would exist in the database, but not in your model.

    builder.Entity< Access >( a =>
    {
        a.Property< int >( "Id" );
        a.HasKey( "Id" );
    } );
Barra answered 30/8, 2021 at 8:6 Comment(0)
T
0

I got the same error while creating a migration when one of my tables had no primary key but 2 Foreign Keys.

In your db context file, you will have to override OnModelCreating function and specify that the table has foreign keys.

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Actor_Movie>().HasKey(am => new
        {
           am.ActorID,
           am.MovieID
        });



        modelBuilder.Entity<Actor_Movie>().HasOne(m => m.Movie)
        .WithMany(am => am.Actor_Movie).HasForeignKey(m => m.MovieID);
        
         modelBuilder.Entity<Actor_Movie>().HasOne(a => a.Actor)
         .WithMany(at => at.Actors_Movies).HasForeignKey(a => a.ActorID);
        
        
         base.OnModelCreating(modelBuilder);

     }

Note Here Table Actor_Movies is the table which has foreign key from Actor Table and Movies Table and both table has a list of Actor_Movies public List<Actor_Movie>? Actor_Movie { get; set; }

Tenebrae answered 22/4, 2022 at 20:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.