我有一个类,其中包含许多IDbSet<SomeClass>
类型的属性:
public InMemoryContext : IContext
{
public IDbSet<ClassA> ClassASet { get; set; }
public IDbSet<ClassB> ClassBSet { get; set; }
[...]
public void SaveChanges()
{
//TODO: this is relevant part
}
}
所有这些属性都在构造函数中实例化:
public InMemoryContext
{
ClassASet = new InMemoryDbSet<ClassA>();
[...]
}
InMemoryDbSet
针对此问题提供了一种相关方法:
public class InMemoryDbSet<T> : IDbSet<T> where T : class
{
public void SaveChanges()
{
[...]
}
}
我希望获得IDbSet
的所有属性并在循环中调用SaveChanges()
,因此我不需要第二次重复所有设置名称。
我尝试过反射,但由于我的属性是通用的,我无法让它工作。我尝试从同一个公共接口派生ClassA
和ClassB
,但仍然没有运气。
实际上是否可以在没有明确指定所有集合的情况下执行此操作?我应该改变什么才能达到这个结果?
我想像伪代码一样:
public void SaveChanges()
{
foreach(var set in GetDbSetsFromClass(this))
{
set.SaveChanges();
}
}
我试过反思:
public void SaveChanges()
{
SaveChangesCalled = true;
var properties = GetType().GetProperties().Where(p => p.PropertyType.IsInterface && typeof(IDbSet<IEntity>).IsAssignableFrom(p.PropertyType)).Cast<InMemoryDbSet<IEntity>>();
foreach (var property in properties)
{
CallSaveChanges(property);
}
}
列表是空的 public bool SaveChangesCalled {get;组; }
private static void CallSaveChanges<T>(InMemoryDbSet<T> set) where T : class
{
set.SaveChanges();
}
编辑:公共属性必须在InMemoryContext
类的顶层保持可见,因为这受到定义EF上下文的接口的限制。
答案 0 :(得分:1)
您的代码无效,因为IDbSet<Class>
无法分配给IDbSet<IEntity>
,因为IDbSet<T>
不是协变的。
您想要的是查找类型为定义定义的属性为IDbSet<>
。
var properties = typeof (InMemoryContext)
.GetProperties()
.Where(p => p.PropertyType.IsGenericType &&
p.PropertyType.GetGenericTypeDefinition() == typeof (IDbSet<>));
要调用CallSaveChanges
方法,您需要:
foreach(var proparty in properties)
{
var value = property.GetValue(this);
var entityType = property.PropertyType.GetGenericArguments().First();
var callSaveChanges = this.GetType()
.GetMethod("CallSaveChanges", BindingFlags.NonPublic | BindingFlags.Static);
var constructedCallSaveChanges = callSaveChanges.MakeGenericMethod(entityType );
constructedCallSaveChanges.Invoke(null, BindingFlags.NonPublic | BindingFlags.Static, null, new object[]{ value }, CultureInfo.InvariantCulture);
}
话虽如此,我不认为这种情况需要反思的使用。
答案 1 :(得分:1)
对于一个简单的解决方案,您可以尝试这样的事情
public InMemoryContext
{
public Dictionary<string, object> allSets = new Dictionary<string, object>();
public InMemoryContext()
{
allSets.Add("classA", new InMemoryDbSet<ClassA>());
allSets.Add("classB", new InMemoryDbSet<ClassB>());
[...]
}
public IDbSet<ClassA> ClassASet { get
{
return allSets["classA"];
}
set
{
allSets["classA"] = Value
}
}
[...]
public void SaveChanges()
{
//TODO: this is relevant part
foreach(var kvp in allSets)
{
kvp.Value.SaveChanges();
}
}
}
有些事情可能是错的,因为它只是我的头脑..但你应该明白