After much more appeared on Google, I found an interesting approach here here . The idea is to create a custom mapping source for LINQ objects, which is nothing more than a pass-through for normal functionality until you reach the table name point.
The exact code of this article did not actually work (except for a simple fixed compilation error or two), because for some reason the TableName property was not actually called. Therefore, I had to explicitly set it in a MetaTable . And since this is a private field, it requires reflection.
What I finished was as follows.
Custom match source
public class CustomMappingSource : MappingSource { private AttributeMappingSource mapping = new AttributeMappingSource(); protected override MetaModel CreateModel(Type dataContextType) { return new CustomMetaModel(mapping.GetModel(dataContextType)); } }
This is just a passage, nothing interesting happens here. But this requires the following level:
Custom metamodel
public class CustomMetaModel : MetaModel { private static CustomAttributeMapping mapping = new CustomAttributeMapping(); private MetaModel model; public CustomMetaModel(MetaModel model) { this.model = model; } public override Type ContextType { get { return model.ContextType; } } public override MappingSource MappingSource { get { return mapping; } } public override string DatabaseName { get { return model.DatabaseName; } } public override Type ProviderType { get { return model.ProviderType; } } public override MetaTable GetTable(Type rowType) { return new CustomMetaTable(model.GetTable(rowType), model); } public override IEnumerable<MetaTable> GetTables() { foreach (var table in model.GetTables()) yield return new CustomMetaTable(table, model); } public override MetaFunction GetFunction(System.Reflection.MethodInfo method) { return model.GetFunction(method); } public override IEnumerable<MetaFunction> GetFunctions() { return model.GetFunctions(); } public override MetaType GetMetaType(Type type) { return model.GetMetaType(type); } }
Again, all the aisles. Nothing interesting until we get to the next level:
Custom meta table
public class CustomMetaTable : MetaTable { private MetaTable table; private MetaModel model; public CustomMetaTable(MetaTable table, MetaModel model) { this.table = table; this.model = model; var tableNameField = this.table.GetType().FindMembers(MemberTypes.Field, BindingFlags.NonPublic | BindingFlags.Instance, (member, criteria) => member.Name == "tableName", null).OfType<FieldInfo>().FirstOrDefault(); if (tableNameField != null) tableNameField.SetValue(this.table, TableName); } public override System.Reflection.MethodInfo DeleteMethod { get { return table.DeleteMethod; } } public override System.Reflection.MethodInfo InsertMethod { get { return table.InsertMethod; } } public override System.Reflection.MethodInfo UpdateMethod { get { return table.UpdateMethod; } } public override MetaModel Model { get { return model; } } public override string TableName { get { return table.TableName .Replace("CRPDTA", ConfigurationManager.AppSettings["BusinessDataSchema"]) .Replace("CRPCTL", ConfigurationManager.AppSettings["ControlDataSchema"]); } } public override MetaType RowType { get { return table.RowType; } } }
What happens is (semi) interesting stuff. The TableName property is still normal, which I wrote based on the original article that I found (linked earlier). All I needed to add was a reflection in the constructor to explicitly specify the table name in the tables.
In doing so, I just needed to configure the use of the data context to use this custom mapping:
using (var db = new BusinessDBContext(ConfigurationManager.ConnectionStrings["BusinessDBConnectionString"].ConnectionString, new CustomAttributeMapping()))