Reputation: 7592
Part 2 problem, which continues from here: EntityFramework Core - Update record fails with DbUpdateConcurrencyException
Error:
The derived type 'BinaryFile' cannot have KeyAttribute on property 'Id' since primary key can only be declared on the root type.
I am trying to make inheritance for my entities as much as possible, so I remove duplication as much as possible.
My inheritance structure:
public interface IEntityMinimum
{
bool IsDeleted { get; set; }
byte[] Version { get; set; }
string CreatedBy { get; set; }
}
public class EntityMinimum : IEntityMinimum
{
public bool IsDeleted { get; set; }
[Timestamp]
public byte[] Version { get; set; }
public string CreatedBy { get; set; }
}
public interface IEntity : IEntityMinimum
{
object Id { get; set; }
DateTime CreatedDate { get; set; }
DateTime? ModifiedDate { get; set; }
string ModifiedBy { get; set; }
}
public interface IEntity<T> : IEntity
{
new T Id { get; set; }
}
public abstract class Entity<T> : EntityMinimum, IEntity<T>
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public T Id { get; set; }
object IEntity.Id
{
get => Id;
set => throw new NotImplementedException();
}
private DateTime? _createdDate;
[DataType(DataType.DateTime)]
public DateTime CreatedDate
{
get => _createdDate ?? DateTime.UtcNow;
set => _createdDate = value;
}
[DataType(DataType.DateTime)]
public DateTime? ModifiedDate { get; set; }
public string ModifiedBy { get; set; }
}
public class EntityMaximum : Entity<int>
{
public bool IsActive { get; set; }
}
public class BinaryFile : EntityMaximum
{
public string Name { get; set; }
public string UniqueName { get; set; }
public Guid UniqueId { get; set; }
public byte[] Content { get; set; }
public virtual ICollection<Campaign> Campaigns { get; set; }
}
I get this error when I use Fluent API to disable isConcurrencyToken
on the Version
field for the EntityMinimum
class like this:
// https://stackoverflow.com/questions/44009020/entity-framework-isrowversion-without-concurrency-check
builder.Entity<EntityMinimum>().Property(x => x.Version).IsRowVersion().IsConcurrencyToken(false);
This is required because I had another issue if I do not disable isConcurrencyToken
on the Version
field:
Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded.
If I remove fluent api configuration, it works, but doesn't update because of Version
field which has [TimeStamp]
attribute.
I have this [TimeStamp]
Version
field in EntityMinimum
to append Version
to every table, so I can use TimeStamp
for synchronisation purposes between mobile and web data.
Am I doing this structure correctly, or should I get rid of [TimeStamp] byte[] Version
and just use string Version
and save DateTime
ticks into it for synchronisation purpose?
Upvotes: 1
Views: 1310
Reputation: 205829
The problem is that the call
builder.Entity<EntityMinimum>()
marks the EntityMinimum
class as entity (part of the EF Core inheritance strategy), while as I understand, you use the base class hierarchy just for implementation purposes.
Instead, you could use the EF Core model metadata services to turn off IsConcurrencyToken
for the Version
property of any real entity derived from EntityMinimum
like this:
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
if (typeof(EntityMinimum).IsAssignableFrom(entityType.ClrType))
entityType.FindProperty("Version").IsConcurrencyToken = false;
}
Upvotes: 3