EF Core выбрасывает «этот тип не может быть интерфейсом сам по себе». - PullRequest
2 голосов
/ 04 февраля 2020

У меня проблемы с EF Core 3.1. с кодом, который работал до недавнего времени. У меня есть этот метод, который вызывается до того, как SaveChanges вызывается для DbContext:

private void SetProps<TEntity>(TEntity dbEntity, EntityState newState)
    where TEntity : class, new()
{
    var entry = this.dbContext.Entry(dbEntity);
    ...
    if (dbEntity is IDbEntityBase dbEntityBase)
    {
        var baseEntry = this.dbContext.Entry(dbEntityBase);
        if (newState == EntityState.Added)
        {
            baseEntry.Property(t => t.Id).CurrentValue = Guid.NewGuid();
        }
    }
}

Большая часть кода оставлена ​​для более удобного чтения, поэтому любые изменения в дизайне будет трудно сделать.

У меня проблема в звонке на baseEntry.Property(t => t.Id).CurrentValue = Guid.NewGuid();. Когда вызывается этот код, EF выдает исключение 'this' type cannot be an interface itself..

IDbEntity - это некоторый базовый интерфейс, который реализуют все классы сущностей (у него есть некоторые общие свойства).

Стек вызовов EF выглядит следующим образом this:

System.ArgumentException: 'this' type cannot be an interface itself.
  at System.RuntimeTypeHandle.VerifyInterfaceIsImplemented(RuntimeTypeHandle interfaceHandle)
  at System.RuntimeType.GetInterfaceMap(Type ifaceType)
  at System.Reflection.RuntimeReflectionExtensions.GetRuntimeInterfaceMap(TypeInfo typeInfo, Type interfaceType)
  at Microsoft.EntityFrameworkCore.Infrastructure.ExpressionExtensions.GetPropertyAccess(LambdaExpression propertyAccessExpression)
  at Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry`1.Property[TProperty](Expression`1 propertyExpression)
  at InDocEdge.Sap.Database.EfContext.SapDbContext.ProcessBeforeSaveChangesData() in C:\MyCode\MyDbContext.cs:line 2
  at InDocEdge.Sap.Database.EfContext.SapDbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken) in C:\MyCode\MyDbContext.cs:line 1

Код работал до недавнего времени, но почему-то теперь EF недоволен (насколько я понимаю) тем, что я предоставляю тип интерфейса для метода Entry, что я считаю возможным.

Кто-нибудь знает, что может быть не так или как решить эту проблему?

1 Ответ

1 голос
/ 04 февраля 2020

Нет просто такой вещи как EntityEntry для типа интерфейса. Это должен быть тип сущности. И EntityEntry<TEntity>.Property необходимо найти свойство типа сущности, а не свойство интерфейса (они концептуально и, возможно, фактически различаются).

Но в обычном случае свойство вашей сущности, реализующее IDbEntityBase.Id, также будет называться Id, и вы можете просто передать это имя entry.Property(string), например:

private void SetProps<TEntity>(TEntity dbEntity, EntityState newState) where TEntity : class, new()
{
    var entry = Entry(dbEntity);

    if (dbEntity is IDbEntityBase)
    {
        if (newState == EntityState.Added)
        {
            entry.Property(nameof(IDbEntityBase.Id)).CurrentValue = Guid.NewGuid();
        }
    }
}

Или, поскольку вы устанавливаете только EntityEntry.CurrentValue, вы можете установить его непосредственно через объект Entity, через ссылка на IDbEntityBase вместо EntityEntry. EG:

    private void SetProps<TEntity>(TEntity dbEntity, EntityState newState) where TEntity : class, new()
    {
        if (dbEntity is IDbEntityBase dbEntityBase)
        {
            if (newState == EntityState.Added)
            {
                dbEntityBase.Id = Guid.NewGuid();
            }
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...