Linq To SQL 下实现动态表名的映射
2009-02-07 11:53 麦舒 阅读(5026) 评论(5) 编辑 收藏 举报这段时间代码写累了,写几篇文章舒缓一下,也算是劳逸结合吧。如果觉得我的文章对你有用,请给点掌声,谢谢。
提出问题
前段时间,在博客园里看到有位朋友,问如何实现在动态表名。我们都知道,把一个实体类映谢到表里,应该这样写:
Code
[Table(Name = "User")]
class User
{
[Column]
public int ID;
[Column]
public string Name;
}
[Table(Name = "User")]
class User
{
[Column]
public int ID;
[Column]
public string Name;
}
很明显,这里的表名是写死的,有些时候,我们可能要根据不同的情况实现不同的表名里加个前缀或者后缀,例如:
tt_User,aa_User,User1、User2。
分析问题
要解决这个问题,首先我们就要明白一个问题,DataContext是如何将实体到表的映射的,事实上,它是例用MappingSource提供的信息来进行映射的。要解决上面的问题,我就是需要重新构一个继承于MappingSource的类。
解决问题
代码如下:
Code
using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml.Schema;
namespace ALinq.Mapping
{
class DynamicMappingSource : MappingSource
{
class DynamicAttributedMetaModel : MetaModel
{
private MetaModel source;
private const string TypeName = "System.Data.Linq.Mapping.AttributedMetaModel";
private DynamicMappingSource mappingSource;
internal DynamicAttributedMetaModel(MappingSource mappingSource, Type contextType)
{
this.mappingSource = (DynamicMappingSource)mappingSource;
var bf = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance;
var args = new object[] { mappingSource, contextType };
source = typeof(DataContext).Assembly.CreateInstance(TypeName, false, bf, null,
args, CultureInfo.CurrentCulture, null) as MetaModel;
Debug.Assert(source != null);
}
public override MetaTable GetTable(Type rowType)
{
if (mappingSource.GetMetaTableName != null)
{
var typeName = "System.Data.Linq.Mapping.AttributedMetaTable";
var bf = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance;
var attribute = new TableAttribute { Name = mappingSource.GetMetaTableName(rowType) };
var args = new object[] { source, attribute, rowType };
var metaTable = typeof(DataContext).Assembly.CreateInstance(typeName, false, bf, null,
args, CultureInfo.CurrentCulture, null) as MetaTable;
return metaTable;
}
return source.GetTable(rowType);
}
public override MetaFunction GetFunction(MethodInfo method)
{
return source.GetFunction(method);
}
public override IEnumerable<MetaTable> GetTables()
{
return source.GetTables();
}
public override IEnumerable<MetaFunction> GetFunctions()
{
return source.GetFunctions();
}
public override MetaType GetMetaType(Type type)
{
return source.GetMetaType(type);
}
public override MappingSource MappingSource
{
get { return source.MappingSource; }
}
public override Type ContextType
{
get { return source.ContextType; }
}
public override string DatabaseName
{
get { return source.DatabaseName; }
}
public override Type ProviderType
{
get { return source.ProviderType; }
}
}
public Func<Type, string> GetMetaTableName;
protected override MetaModel CreateModel(Type dataContextType)
{
if (dataContextType == null)
{
throw new ArgumentNullException("dataContextType");
}
return new DynamicAttributedMetaModel(this, dataContextType);
}
}
[Table(Name = "User")]
class User
{
[Column]
public int ID;
[Column]
public string Name;
}
class Program
{
static void Main(string[] args)
{
var mappingSource = new DynamicMappingSource();
int i = 0;
mappingSource.GetMetaTableName = delegate(Type type)
{
var att = type.GetCustomAttributes(typeof(TableAttribute), true).Single()
as TableAttribute;
Debug.Assert(att != null);
return att.Name + i;
};
var constr = @"Data Source=NOTEBOOK\SQLEXPRESS;Initial Catalog=DemoDataContext;Integrated Security=True";
var context = new DataContext(constr, mappingSource) { Log = Console.Out };
i = 1;
context.GetTable<User>().Select(o => o).ToList();
i = 2;
context.GetTable<User>().Select(o => o).ToList();
}
}
}
using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml.Schema;
namespace ALinq.Mapping
{
class DynamicMappingSource : MappingSource
{
class DynamicAttributedMetaModel : MetaModel
{
private MetaModel source;
private const string TypeName = "System.Data.Linq.Mapping.AttributedMetaModel";
private DynamicMappingSource mappingSource;
internal DynamicAttributedMetaModel(MappingSource mappingSource, Type contextType)
{
this.mappingSource = (DynamicMappingSource)mappingSource;
var bf = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance;
var args = new object[] { mappingSource, contextType };
source = typeof(DataContext).Assembly.CreateInstance(TypeName, false, bf, null,
args, CultureInfo.CurrentCulture, null) as MetaModel;
Debug.Assert(source != null);
}
public override MetaTable GetTable(Type rowType)
{
if (mappingSource.GetMetaTableName != null)
{
var typeName = "System.Data.Linq.Mapping.AttributedMetaTable";
var bf = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance;
var attribute = new TableAttribute { Name = mappingSource.GetMetaTableName(rowType) };
var args = new object[] { source, attribute, rowType };
var metaTable = typeof(DataContext).Assembly.CreateInstance(typeName, false, bf, null,
args, CultureInfo.CurrentCulture, null) as MetaTable;
return metaTable;
}
return source.GetTable(rowType);
}
public override MetaFunction GetFunction(MethodInfo method)
{
return source.GetFunction(method);
}
public override IEnumerable<MetaTable> GetTables()
{
return source.GetTables();
}
public override IEnumerable<MetaFunction> GetFunctions()
{
return source.GetFunctions();
}
public override MetaType GetMetaType(Type type)
{
return source.GetMetaType(type);
}
public override MappingSource MappingSource
{
get { return source.MappingSource; }
}
public override Type ContextType
{
get { return source.ContextType; }
}
public override string DatabaseName
{
get { return source.DatabaseName; }
}
public override Type ProviderType
{
get { return source.ProviderType; }
}
}
public Func<Type, string> GetMetaTableName;
protected override MetaModel CreateModel(Type dataContextType)
{
if (dataContextType == null)
{
throw new ArgumentNullException("dataContextType");
}
return new DynamicAttributedMetaModel(this, dataContextType);
}
}
[Table(Name = "User")]
class User
{
[Column]
public int ID;
[Column]
public string Name;
}
class Program
{
static void Main(string[] args)
{
var mappingSource = new DynamicMappingSource();
int i = 0;
mappingSource.GetMetaTableName = delegate(Type type)
{
var att = type.GetCustomAttributes(typeof(TableAttribute), true).Single()
as TableAttribute;
Debug.Assert(att != null);
return att.Name + i;
};
var constr = @"Data Source=NOTEBOOK\SQLEXPRESS;Initial Catalog=DemoDataContext;Integrated Security=True";
var context = new DataContext(constr, mappingSource) { Log = Console.Out };
i = 1;
context.GetTable<User>().Select(o => o).ToList();
i = 2;
context.GetTable<User>().Select(o => o).ToList();
}
}
}
把运行后的结果给大家看一下:
从上图可以看到,表名已经由原来的User分别变为了User1和User2。