0

I am working on an application that uses Clean Architecture in .net core. The domain entities are inherited from AggregateRoot which is further inherited with the Entity class. This entity class has Id field which means I now have Id in all my domain entities. It works fine if all my domain entities have an Id field. Below is the code sample.

public abstract class Entity : IEquatable<Entity>
{
    protected Entity(int id) => Id = id;

    protected Entity()
    {
    }
}

public abstract class AggregateRoot : Entity
{
    protected AggregateRoot(int id)
        : base(id)
    {
    }
}

public sealed class User : AggregateRoot
{

}

public sealed class Directory : AggregateRoot
{

}

I have a different way of handling the Id fields. I am using the DomainEntityName+Id. e.g., For entities User & Directory has UserId & DirectoryId respectively. I have the same ids in the database as well. I don't want to use the Id field and want to replace it with UserId or DirectoryId. Please suggest how can I achieve this.

I did try to keep both fields and populate both with the value from the database using the configuration below:

builder
.Property(x => x.DirectoryId)
.HasColumnName("DirectoryId");

builder
.Property(x => x.Id)
.HasColumnName("DirectoryId")
.ValueGeneratedNever();

but this has thrown the exception:

System.InvalidOperationException: 'Directory.DirectoryId' and 'Directory.Id' are both mapped to column 'DirectoryId' in 'Directories', but the properties are contained within the same hierarchy. All properties on an entity type must be mapped to unique different columns.

Edited Question:

public class Directory : AggregateRoot  
{       
    [NotMapped]         
    public int DirectoryId { get; init; }       
    public string Name { get; init; } = string.Empty;   
} 

public void Configure(EntityTypeBuilder<Directory> builder)     
{       
    builder.Property(x => x.DirectoryId).HasColumnName("DirectoryId");          
    builder.Property(x => x.Id).HasColumnName("DirectoryId").ValueGeneratedNever();     
}

The AggregateRoot has an Entity class with Id field. With this change the DirectoryId is set with zero value.

Imran Yaseen
  • 543
  • 1
  • 5
  • 20
  • Add these DirectoryId, etc. to your classes in question. Simple solution make `Id` or `DirectoryId` as `[NotMapped]`, but point them to same storage (field). – Svyatoslav Danyliv Jun 23 '23 at 15:25
  • The field with `[NotMapped]` is always zero. It doesn't get the value from Entity Framework. – Imran Yaseen Jun 26 '23 at 09:13
  • Show what you have tried. – Svyatoslav Danyliv Jun 26 '23 at 13:54
  • Hi @Svyatoslav, I have Directory entity which has a DirectoryId and a base Entity has Id field. The DirectoryId comes from the database. I have set the Directory entity as you suggested. [NotMapped] public int DirectoryId { get; private set; } For the configuration i have done the following configuration. builder .Property(x => x.DirectoryId) .HasColumnName("DirectoryId"); builder .Property(x => x.Id) .HasColumnName("DirectoryId") .ValueGeneratedNever(); but it sets DirectoryId with zero value. – Imran Yaseen Jun 26 '23 at 14:40
  • Please less words, correct original classes in question, it is more informative. – Svyatoslav Danyliv Jun 26 '23 at 14:42
  • Better edit question. In comments it is not readable. – Svyatoslav Danyliv Jul 03 '23 at 09:56
  • Hi @Svyatoslav, here you go. `public class Directory : AggregateRoot { [NotMapped] public int DirectoryId { get; init; } public string Name { get; init; } = string.Empty; }` and `public void Configure(EntityTypeBuilder builder) { builder.Property(x => x.DirectoryId).HasColumnName("DirectoryId"); builder.Property(x => x.Id).HasColumnName("DirectoryId").ValueGeneratedNever(); }` – Imran Yaseen Jul 03 '23 at 10:24
  • Edit original question NOT comment. – Svyatoslav Danyliv Jul 03 '23 at 10:41
  • Correct me if I'm wrong. you have User class which has Id as primary key and it's generating Column 'Id' in database aswell, However, you want it to generate column 'UserId ' as primary key in database? – Pouya Hashemi Jul 11 '23 at 08:43
  • @PouyaHashemi, The database table Directories has a DirectoryId field what I want is for the DirectoryId & Id fields should be populated with the DirectoryId field from SQL while loading entity through EF Core. – Imran Yaseen Jul 11 '23 at 09:14
  • So Your class has DirectoryId and Id property and also your table has DirectoryId and Id. and you want your table have only directoryId as primary key? so you can use directoryId to query data? – Pouya Hashemi Jul 11 '23 at 09:32
  • @PouyaHashemi, please understand my problem. I have DirectoryId and Id in my class. In the table, I have only DirectoryId which is a primary. What i want is when the Directory entity would load it assign DirectoryId value to both DirectoryId as well as Id fields. – Imran Yaseen Jul 11 '23 at 10:12
  • if you want your directoryId has the same value as the id you can make the directoryId column as computed column. to do this you should configure it in dbcontext.OnModelCreating like this: builder.Property(p => p.DirectoryId).HasComputedColumnSql("id") – Pouya Hashemi Jul 11 '23 at 10:20

1 Answers1

0

I would suggest to reuse Id property storage and do not map DirectoryId do database:

public class Directory : AggregateRoot  
{       
    public int DirectoryId { get => Id; init => Id = value; }
    public string Name { get; init; } = string.Empty;   
} 

public void Configure(EntityTypeBuilder<Directory> builder)     
{       
    builder.Ignore(c => c.DirectoryId);
    builder.Property(x => x.Id).HasColumnName("DirectoryId").ValueGeneratedNever();     
}
Svyatoslav Danyliv
  • 21,911
  • 3
  • 16
  • 32