为了使这是真正的透明,你必须跳过一些非常疯狂的篮球,但它可以通过覆盖所有的Meta***
具有您自己派生类型的类。
这对于像Castle这样的代理/方法拦截库实际上相当简单,但是假设这里是最低公分母,它基本上是一个漫长而无聊的实施每一个元方法来包装原始类型的考验,因为你可以不直接从任何属性映射类派生。
我会尽量坚持这里的重要覆盖;如果您在下面的代码中没有看到特定的方法/属性,则意味着该实现实际上是包装“内部”方法/属性并返回结果的单线程。我在PasteBin上发布了所有内容,单行方法和全部内容,以便您可以剪切/粘贴以进行测试/实验。
你首先需要的是一个快速重写声明,它看起来像这样:
class TableOverride
{
public TableOverride(Type entityType, string tableName)
{
if (entityType == null)
throw new ArgumentNullException("entityType");
if (string.IsNullOrEmpty(tableName))
throw new ArgumentNullException("tableName");
this.EntityType = entityType;
this.TableName = tableName;
}
public Type EntityType { get; private set; }
public string TableName { get; private set; }
}
现在的元类。从最低级开始,你必须实现一个MetaType
包装:
class OverrideMetaType : MetaType
{
private readonly MetaModel model;
private readonly MetaType innerType;
private readonly MetaTable overrideTable;
public OverrideMetaType(MetaModel model, MetaType innerType,
MetaTable overrideTable)
{
if (model == null)
throw new ArgumentNullException("model");
if (innerType == null)
throw new ArgumentNullException("innerType");
if (overrideTable == null)
throw new ArgumentNullException("overrideTable");
this.model = model;
this.innerType = innerType;
this.overrideTable = overrideTable;
}
public override MetaModel Model
{
get { return model; }
}
public override MetaTable Table
{
get { return overrideTable; }
}
}
同样,你必须完成这个约30属性/方法,我已经排除了那些刚刚return innerType.XYZ
。还在我这儿?好的,接下来是MetaTable
:
class OverrideMetaTable : MetaTable
{
private readonly MetaModel model;
private readonly MetaTable innerTable;
private readonly string tableName;
public OverrideMetaTable(MetaModel model, MetaTable innerTable,
string tableName)
{
if (model == null)
throw new ArgumentNullException("model");
if (innerTable == null)
throw new ArgumentNullException("innerTable");
if (string.IsNullOrEmpty(tableName))
throw new ArgumentNullException("tableName");
this.model = model;
this.innerTable = innerTable;
this.tableName = tableName;
}
public override MetaModel Model
{
get { return model; }
}
public override MetaType RowType
{
get { return new OverrideMetaType(model, innerTable.RowType, this); }
}
public override string TableName
{
get { return tableName; }
}
}
是的,无聊。好的,接下来是MetaModel
本身。这里有一些更有趣的事情,这是我们真正开始宣称替代的地方:
class OverrideMetaModel : MetaModel
{
private readonly MappingSource source;
private readonly MetaModel innerModel;
private readonly List<TableOverride> tableOverrides = new
List<TableOverride>();
public OverrideMetaModel(MappingSource source, MetaModel innerModel,
IEnumerable<TableOverride> tableOverrides)
{
if (source == null)
throw new ArgumentNullException("source");
if (innerModel == null)
throw new ArgumentNullException("innerModel");
this.source = source;
this.innerModel = innerModel;
if (tableOverrides != null)
this.tableOverrides.AddRange(tableOverrides);
}
public override Type ContextType
{
get { return innerModel.ContextType; }
}
public override string DatabaseName
{
get { return innerModel.DatabaseName; }
}
public override MetaFunction GetFunction(MethodInfo method)
{
return innerModel.GetFunction(method);
}
public override IEnumerable<MetaFunction> GetFunctions()
{
return innerModel.GetFunctions();
}
public override MetaType GetMetaType(Type type)
{
return Wrap(innerModel.GetMetaType(type));
}
public override MetaTable GetTable(Type rowType)
{
return Wrap(innerModel.GetTable(rowType));
}
public override IEnumerable<MetaTable> GetTables()
{
return innerModel.GetTables().Select(t => Wrap(t));
}
private MetaTable Wrap(MetaTable innerTable)
{
TableOverride ovr = tableOverrides.FirstOrDefault(o =>
o.EntityType == innerTable.RowType.Type);
return (ovr != null) ?
new OverrideMetaTable(this, innerTable, ovr.TableName) :
innerTable;
}
private MetaType Wrap(MetaType innerType)
{
TableOverride ovr = tableOverrides.FirstOrDefault(o =>
o.EntityType == innerType.Type);
return (ovr != null) ?
new OverrideMetaType(this, innerType, Wrap(innerType.Table)) :
innerType;
}
public override MappingSource MappingSource
{
get { return source; }
}
}
我们差不多完成了!现在你只需要映射源:
class OverrideMappingSource : MappingSource
{
private readonly MappingSource innerSource;
private readonly List<TableOverride> tableOverrides = new
List<TableOverride>();
public OverrideMappingSource(MappingSource innerSource)
{
if (innerSource == null)
throw new ArgumentNullException("innerSource");
this.innerSource = innerSource;
}
protected override MetaModel CreateModel(Type dataContextType)
{
var innerModel = innerSource.GetModel(dataContextType);
return new OverrideMetaModel(this, innerModel, tableOverrides);
}
public void OverrideTable(Type entityType, string tableName)
{
tableOverrides.Add(new TableOverride(entityType, tableName));
}
}
现在,我们终于可以开始使用这个(唷):
var realSource = new AttributeMappingSource();
var overrideSource = new OverrideMappingSource(realSource);
overrideSource.OverrideTable(typeof(Customer), "NewCustomer");
string connection = Properties.Settings.Default.MyConnectionString;
using (MyDataContext context = new MyDataContext(connection, overrideSource))
{
// Do your work here
}
我已经与查询与插入(InsertOnSubmit
)测试这和也。在我非常基本的测试中,有可能,实际上很可能我错过了一些东西。哦,这只会工作,如果两个表字面上确切相同,列名和所有。
如果此表有任何关联(外键),可能会搞砸,因为您必须重写关联名称,两个都结束。我会把这个作为练习留给读者,因为考虑它会让我头痛。从这个特定的表格中删除任何关联可能会更好,所以您不必处理这些头痛的问题。
玩得开心!
请您澄清一下吗? – 2010-04-29 15:22:54
没有选择转移到EF? – 2010-05-06 07:35:18