提取实例
我担心这将是一个简单的问题,一个很大的设置。至于答案的复杂性,我怕什么,我可能会进入...提取实例
我建立将被用于帮助从源数据库具有一个表结构,不同的转换数据到目标数据库的应用程序结构体。目标数据库将包含的数据已经,因此处理必须能够插入到目标,在新插入的项目将获得新的ID时,维持从源头基于ID的关系。假设每个源表都可以转换为单个目标表。
最小码,必要的类/接口结构:
public interface IDataSetStorable { }
public class InMemoryDataSet : List<IDataSetStorable>
{
public AbstractDataEntity FindEntity(string id, Type type)
{
// The question will be about this method
return new object() as AbstractDataEntity;
}
}
public class EntityList<T> : Dictionary<string, T>, IDataSetStorable where T : AbstractDataEntity
{
public void AddEntity(T entity)
{
this.Add(entity.ID, entity);
}
}
public abstract class AbstractDataEntity
{
public string ID { get; set; }
}
public abstract class DataItem<S, T> : AbstractDataEntity { }
// There will be a set of these three classes per source DB table
public class SourceType { }
public class TargetType { }
public class TransformationType : DataItem<SourceType, TargetType> { }
InMemoryDataSet
保持的表中,通过(例如)EntityList<TransformationType>
实例表示。会有的SourceType
每个映射到TargetType
,其中每个的那些可能是从一个DataContext的类的TransformationType
。每个源数据库表将有一个,尽管其中许多表可能映射到单个目标数据库表。
使用IDataSetStorable
作为标记接口允许在InMemoryDataSet
的实例内存储具有许多不同亚型的EntityList<>
。
在从源数据库的任何项目的改造,它只能插入到目标数据库,如果我们知道它的外键适当的目标-DB的ID。为此,代码将从源数据库中查找所有依赖项,并在尝试转换正在考虑的项目之前对其进行转换。递归,这应该能保证插入到目标数据库的第一件事情有没有依赖关系,让他们的新的ID,并且将依赖于他们的东西时就可以进行查找。
的InMemoryDataSet
实例将提供查找设施,这应传递的ID(从源DB)和Type
类型的参数,表示与变换项的类型交易的TransformationType
被查找。
的实施例:Table1
具有两个字段,id
和table2_id
,后者引用Table2
,其场id
。查找呼叫将是(有点伪-Y):
var entity = myDataSet.FindEntity([table1.table2_id], typeof(Table2TransformationType));
然后entity
应Table2TransformationType
类型(从AbstractDataEntity
最终继承)的,并且将来自与Table2
ID匹配传递给该方法表示的行。
最后,到了一个问题:
在FindEntity()
方法,我怎么能找到,如果有一个EntityList<whatever the passed type was>
礼物?我的想法是使用类似的东西:
foreach (var entityList in this)
{
// work out if entityList is an EntityList<passed-in type>;
}
简单的问题!但我不知道我该怎么做这最后一部分:(
您需要检查:
- 如果
Type
当前项目entityList
代表通用类型 - 如果该通用类型表示
EntityList<>
- 如果该类型的泛型参数是传入的YPE
试试这个:
if (entityList.GetType().IsGenericType &&
entityList.GetType().GetGenericTypeDefinition() == typeof(EntityList<>) &&
entityList.GetType().GetGenericArguments()[0] == type)
{
...
}
编辑:是越来越通用的参数出现在错误的类型。固定。
使用LINQ:
Dictionary<string, Type> a = new Dictionary<string, Type>();
var allOfMyType = a.Where(x=> (x.Value.Name == "MyType"));
好的,设法让这项工作使用了一点思考。柯克沃尔让我开始寻找正确的地方,但最终解决方案没有使用他的建议。使用Type.GetMethod()
时有一个附加的方法,public T RetrieveEntity(string id)
,在顺序EntityList<T>
类,使其更容易获得单个项目出Dictionary
通过关键的:
public class EntityList<T> : Dictionary<string, T>, IDataSetStorable where T : AbstractDataEntity
{
public void AddEntity(T entity)
{
this.Add(entity.ID, entity);
}
public T RetrieveEntity(string id)
{
return this[id];
}
}
然后我们有FindEntity(string id, Type type)
方法的胆量:
public class InMemoryDataSet : List<IDataSetStorable>
{
public AbstractDataEntity FindEntity(string id, Type type)
{
// Make an instance of the passed-in type so that invoking
// TryGetValue will throw an exception if operating on an
// EntityList which is not of the correct type.
var sample = type.GetConstructor(new Type[]{}).Invoke(new object[]{});
foreach (var entityList in this)
{
try
{
// This doesn't manage to set sample to the found entity...
bool idFound = (bool)entityList.GetType().GetMethod("TryGetValue").Invoke(entityList, new object[] { id, sample });
if (idFound)
{
// So we dig it out here with the method added to EntityList<>
sample = entityList.GetType().GetMethod("RetrieveEntity").Invoke(entityList, new object[] { id });
return (AbstractDataEntity)sample;
}
}
catch (Exception ex)
{
// Likely some kind of casting exception
}
}
return null;
}
}
在调用FindEntity()
点,我们知道需要的类型是什么,所以铸造AbstractDataEntity
它返回的是微不足道的。
绝对到达那里。前两个陈述评估为“真实”,但第三个陈述并非如此。看起来'entityList.GetType().GetGenericTypeDefinition().GetGenericArguments()[0])从'EntityList'的原始声明中返回'T',而不是'EntityList'创建的特定类型。有没有尝试将'entityList'变量转换为'EntityList '的方法,如果它不合适会抛出异常? –
2010-10-14 10:05:56
@Matt,我的道歉,我应该先测试一下。我更新了答案,但得到了错误类型的泛型参数。现在应该工作。 – 2010-10-14 13:48:19
钉上它+1,并标记为已接受。我自己的答案是有效的,但是你的答案早一些,而且比依靠Invoke的一个转换异常更加整洁! – 2010-10-15 15:47:05