繁体   English   中英

强制转换自引用实体,检测泛型

[英]Casting of self-referencing entities, detect generic type

一次,我得到了所有实体的接口:

public interface IEntity
{
    int Id { get; set; }
}

对于某些实体,将存在一个突变表以记录为哪个实体(CRUD)所做的工作

public interface IMutation<TEntity> where TEntity : IEntity
{
    ICollection<Mutation<TEntity>> Mutations { get; set; }
}

对于实现IMutation每个实体,实体框架都会创建一个名称为Mutation<EntityName>的表。因此, Mutation<EntityName>也是一个实体。

public class Mutation<TEntity> : Entity where TEntity : IEntity
{
    public int EntityId { get; set; }
    public TEntity Entity { get; set; }
}

我在一个类上实现了接口IEntity ,该类将继承某些实体。

public class Entity : IEntity
{
    public int Id { get; set; }
}

实体Test继承自Entity (因为它是一个实体),并通过引用自身实现IMutation

public class Test : Entity, IMutation<Test>
{
    public ICollection<Mutation<Test>> Mutations { get; set; } = new List<Mutation<Test>>();
}

实体框架将其获取,并创建两个表:

  • 使用属性IdName Test
  • 具有属性Id (来自IEntity的PK)和EntityId (引用Test IEntity的FK)的Mutation<Test>

这一切都很好。 DB模式等等。

所以我想做的是,总是要更改一个实现IMutation<EntityName>实体,然后创建一个新的数据集。 可以覆盖DbContext的SaveChanges 很好,所以我尝试了:

public override int SaveChanges()
{
    IEnumerable<EntityEntry> entries = ChangeTracker.Entries(); // gets me all entries that were changed

    IEnumerable<IEntity> mutationEntries =
        entries.Select(s => s.Entity).Where(
            w =>
                w.GetType()
                    .GetInterfaces()
                    .Any(
                        x =>
                            x.GetTypeInfo().IsGenericType && x.GetGenericTypeDefinition() == typeof(IMutation<>)))
                            .Select(s => (IEntity)s);

    // so here now I got the entries that implement IMutation<?> <-- call this now ?-type
    // what I'd now want to do is:
    foreach(var entry in mutationEntries)
    {
        IMutation<?> mutationEntry = (IMutation<?>)entry;
        mutationEntry.Mutations.Add(new Mutation<?>{ /* later on, add here CRUD, Id, user who changed,... */ });
    }
    return base.SaveChanges();
}

现在的问题是,我不知道我的?-Type是什么。 我知道它必须来自Type IEntity 但是,当我尝试将Entity解析为IMutation<IEntity>我得到一个错误,说他不能从IMutation<Test>IMutation<IEntity> (但是Test实现IEntity

尝试过这种方式:

IEnumerable<IMutation<IEntity>> mutationEntries =
        entries.Select(s => s.Entity).Where(
            w =>
                w.GetType()
                    .GetInterfaces()
                    .Any(
                        x =>
                            x.GetTypeInfo().IsGenericType && x.GetGenericTypeDefinition() == typeof(IMutation<>)))
                            .Select(s => (IMutation<IEntity>)s);

但是我已经在检查我的实体是否实现IMutation 也许有人有主意,我该如何解决这个问题?

使用非协变且没有非通用对应项的通用接口(如IEnumerable<T> -> IEnumerableIQueryable<T> -> IQueryable等)很难工作。

在这种情况下,唯一剩下的选择是反射或动态调度。

例如,您可以添加如下方法:

private void ProcessMutationEntity<TEntity>(TEntity entity)
    where TEntity : IEntity, IMutation<TEntity>
{
    entity.Mutations.Add(new Mutation<TEntity> { EntityId = entity.Id, Entity = entity});
}

然后使用DLR调用它(使用第一个示例中的代码):

// ...
foreach (var entry in mutationEntries)
{
    ProcessMutationEntity((dynamic)entry);
}
// ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM