我们假设我针对数据库生成Linq to SQL上下文,以便为应用程序进行一些简单的数据访问。该数据库中的表属于特定模式(在本例中为#34; CRPDTA"对于某些表," CRPCTL"对于其他表)。但是,当应用程序投入生产时,相同的表将属于生产数据库中的不同模式(在本例中为" PRODTA"和" PRODCTL")。
有没有办法让Linq 2 SQL可以配置模式名称,这在应用程序的配置文件中是可以定义的?
在数据上下文类中,我看到了表名属性:
[global::System.Data.Linq.Mapping.TableAttribute(Name="CRPDTA.TableName")]
从技术上讲,我可以直接操作该字符串,但编辑自动生成的文件意味着需要在重新生成时重新编辑它。所以我更喜欢更具可持续性的东西。但到目前为止还没有找到类似的东西。
这是否可以通过此工具完成?也许有人有一个创造性的解决方案,在类似的情况下工作?
答案 0 :(得分:3)
经过更多关于Google的讨论之后,我终于找到了一个有趣的方法here。我们的想法是为LINQ实体创建一个自定义映射源,这只不过是正常功能的传递,直到你到达表名的位置。
该文章的确切代码实际上并没有起作用(除了一个容易修复的编译错误或两个),因为由于某种原因,实际上没有调用TableName
属性。所以我必须在MetaTable
对象中明确设置它。而且由于它是一个私人领域,这需要反思。
我最终得到的结论如下。
自定义映射源
public class CustomMappingSource : MappingSource
{
private AttributeMappingSource mapping = new AttributeMappingSource();
protected override MetaModel CreateModel(Type dataContextType)
{
return new CustomMetaModel(mapping.GetModel(dataContextType));
}
}
这只是一个传递,这里没有什么有趣的事情发生。但它确实需要下一个级别:
自定义元模型
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);
}
}
再次,所有传递。没有什么有趣的,直到我们进入下一个级别:
自定义元表
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; }
}
}
这就是(半)有趣的事情发生的地方。 TableName
属性仍然是我根据我发现的原始文章(之前链接)编写的自定义属性。我需要添加的只是构造函数中的反射,以在表上显式设置表名。
有了这个,我只需要设置我的数据上下文用法来使用这个自定义映射:
using (var db = new BusinessDBContext(ConfigurationManager.ConnectionStrings["BusinessDBConnectionString"].ConnectionString, new CustomAttributeMapping()))