Чтобы сделать это по-настоящему прозрачным, вы должны перепрыгнуть через несколько довольно сумасшедших обручей, но это можно сделать, переопределив все классы Meta***
вашими производными типами.
Это на самом деле было бы довольно просто с библиотекой перехвата прокси / метода, такой как Castle, но при условии наименьшего общего знаменателя здесь, это в основном долгое и скучное испытание реализации каждого мета-метода для переноса исходного типа, потому что t наследуется напрямую от любого из классов отображения атрибутов.
Я постараюсь придерживаться важных переопределений здесь; если вы не видите какой-либо конкретный метод / свойство в приведенном ниже коде, это означает, что реализация является буквально однострочной, которая оборачивает «внутренний» метод / свойство и возвращает результат. Я разместил все это, однострочные методы и все, на 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
). Возможно, на самом деле довольно вероятно, что я что-то пропустил в самом базовом тестировании. О, и это будет работать, только если две таблицы буквально точно одинаковы, имена столбцов и все.
Вероятно, возникнет ошибка, если в этой таблице есть какие-либо ассоциации (внешние ключи), поскольку вам также придется переопределять имена ассоциаций, в оба заканчиваются. Я оставлю это в качестве упражнения для читателя, так как от размышлений об этом у меня болит голова. Вам, вероятно, было бы лучше просто удалить любые ассоциации из этой конкретной таблицы, поэтому вам не придется иметь дело с этой головной болью.
Веселись!