'ASP.NET model that requires a reference to a IdentityUser?

I have a model Blueprint that requires a reference to an IdentityUser. When I run Add-Migration CreateBlueprintSchema the following error is thrown:

No suitable constructor was found for entity type 'Blueprint'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'author' in 'Blueprint(IdentityUser author, string name, string data)'.

How do I resolve this issue?

Blueprint.cs

using Microsoft.AspNetCore.Identity;
using System.ComponentModel.DataAnnotations;
using System.Security.Cryptography;
using System.Text;

namespace FactorioStudio.Models
{
    public class Blueprint
    {
        [MaxLength(40)]
        public string Id { get; set; }

        [Required]
        public string Name { get; set; }

        [Required]
        public string Data { get; set; }

        [Required]
        public IdentityUser Author { get; set; }

        [Required]
        public DateTime CreationDate { get; set; }

        public Blueprint? ParentBlueprint { get; set; }

        public Blueprint(IdentityUser author, string name, string data)
        {
            Author = author;
            Name = name;
            Data = data;
            CreationDate = DateTime.UtcNow;

            string hashSource = Author.Id +
                Name +
                CreationDate.ToString("s", System.Globalization.CultureInfo.InvariantCulture) +
                Data;

            using SHA1 sha1 = SHA1.Create();
            byte[] hashBytes = sha1.ComputeHash(Encoding.UTF8.GetBytes(hashSource));
            string hash = BitConverter.ToString(hashBytes).Replace("-", String.Empty).ToLower();
            Id = hash;
        }
    }
}


Solution 1:[1]

change your model like this:

public class Blueprint
    {
        [MaxLength(40)]
        public string Id { get; set; }

        [Required]
        public string Name { get; set; }

        [Required]
        public string Data { get; set; }

        [Required]
        public IdentityUser Author { get; set; } = new IdentityUser();

        //.......
   }

or just add a non-parameter constructor in your model.

You can refer to this;

Edit=======================

For testing convenience, I manually added a foreign key(If I don't add Fk by myself, EF core will create shadow foreign key property, But i can't use it directly), Then I create a Blueprint without referring to an existing IdentityUser, You can see it will report a SqlException that show error in FK.

enter image description here

Solution 2:[2]

As I wrote in the comment, EF Core cannot set navigation properties using a constructor. Instead, use a custom value generator to create the hash for the ID when saving the entity.

    public class BlueprintHashGenerator : ValueGenerator<string>
    {
        public override bool GeneratesTemporaryValues => false;

        public override string Next(EntityEntry entry)
        {
            if (entry.Entity is not Blueprint bp)
            {
                throw new ApplicationException("Unexpected entity");
            }

            string hashSource = bp.Author.Id +
                bp.Name +
                bp.CreationDate.ToString("s", System.Globalization.CultureInfo.InvariantCulture) +
                bp.Data;

            using SHA1 sha1 = SHA1.Create();
            byte[] hashBytes = sha1.ComputeHash(Encoding.UTF8.GetBytes(hashSource));
            return BitConverter.ToString(hashBytes).Replace("-", String.Empty).ToLower();
        }
    }

then in model builder

builder.Entity<Blueprint>().Property(bp => bp.Id).HasValueGenerator<BlueprintHashGenerator>().ValueGeneratedNever();

It will generate the value on SaveChanges, so ensure all properties are set before calling save (Author, Name, CreationDate, Data).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2