有一次,我为所有实体提供了一个界面:
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>>();
}
实体框架获取它,并创建两个表:
Test
包含属性Id
和Name
Mutation<Test>
包含属性Id
(来自IEntity
的PK)和EntityId
(FK引用Test
- 实体)这一切都很棒。数据库架构等等。
所以我想要做的是,总是,当一个实体改变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。我知道它必须来自IEntity
类型。
但是,当我尝试将实体解析为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
。
也许有人有一个想法,我怎么能解决这个问题?
答案 0 :(得分:2)
很难使用非协变且没有非通用对应物的通用接口(例如IEnumerable<T>
- &gt; IEnumerable
,IQueryable<T>
- &gt; 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);
}
// ...