1

I have generic structure for my rest API that is built on .net core 3.0

Here is my code for generic entities.

public interface IFullAuditedEntity
{
    object Id { get; set; }
}

public abstract class FullAuditedEntity<T> : IFullAuditedEntity where T : struct
{
    public IFullAuditedEntity() { }

    [Key]
    public virtual T Id { get; set; }

    object Entity.Id
    {
        get { return Id; }
        set
        {
            Id = (T)value;
        }
    }
}

Now, this structure works fine for me if my entity has int primary key.

But If I have to use string as a primary key, it gives me generics error. see below entity.

[Table(name: "Status")]
public class Status : FullAuditedEntity<string>
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
    [Required]
    [StringLength(03)]
    public override string Id { get; set; }

    [StringLength(03)]
    public string Type { get; set; }

}

See added snap for more information.

enter image description here

I tried to pass Nullable as some of other SO answers suggested but it didn't work for me, so any help would be really appreciated.

Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
Bharat
  • 5,869
  • 4
  • 38
  • 58
  • 2
    Where is the declaration of `FullAuditedEntity`? Assuming it derives from `Entity`, that's not going to work as `string` isn't a value type at all, nullable or non-nullable. – Jon Skeet Nov 18 '19 at 07:32
  • So, this FullAuditedEntity is Entity in given example.. – Bharat Nov 18 '19 at 07:33
  • 2
    "So, this FullAuditedEntity is Entity in given example.." I don't know what you mean by that. Please make sure you provide all the relevant code in your post. – Jon Skeet Nov 18 '19 at 07:34
  • 1
    `string` is for all intents and purposes immutable, but it is still a reference type. – ProgrammingLlama Nov 18 '19 at 07:35
  • Jon, I have updated my question. – Bharat Nov 18 '19 at 07:35
  • 3
    Right. So it's just that `FullAuditedEntity` requires the type argument to be a non-nullable value type, whereas `string` is a reference type. There's not much more we can say about that - you need to work out *why* the constraint is there to start with. – Jon Skeet Nov 18 '19 at 07:38

1 Answers1

4

There is a constraint:

public abstract class Entity<T> : IEntity where T : struct

so string is not type of struct, string is a reference type. What's the difference between struct and class in .NET?

As msdn says:

Constraints inform the compiler about the capabilities a type argument must have. Without any constraints, the type argument could be any type. The compiler can only assume the members of System.Object, which is the ultimate base class for any .NET type. For more information, see Why use constraints.

You can remove this constraint to avoid this error and now your Id can be any type:

public abstract class Entity<T> : IEntity

As an alternative to string type of key and if it is eligible for your case, you can create T type of Guid. If it can be type of Guid, then you can avoid deletion of constraint:

public abstract class FullAuditedEntity<T> : IFullAuditedEntity where T : struct
{
     // ... The code is omitted for the brevity
}

and your entity:

[Table(name: "Status")]
public class Status : FullAuditedEntity<string>
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
    [Required]
    [Guid]
    public override Guid Id { get; set; }
StepUp
  • 36,391
  • 15
  • 88
  • 148