Linq To SQL 下实现动态表名的映射

提出问题

前段时间,看到有位朋友,问如何实现在动态表名。我们都知道,把一个实体类映谢到表里,应该这样写:

 

Code
    [Table(Name = "User")]
    
class User
    {
        [Column]
        
public int ID;

        [Column]
        
public string Name;

    }

 

很明显,这里的表名是写死的,有些时候,我们可能要根据不同的情况实现不同的表名里加个前缀或者后缀,例如:

tt_User,aa_User,User1、User2。

分析问题

要解决这个问题,首先我们就要明白一个问题,DataContext是如何将实体到表的映射的,事实上,它是例用MappingSource提供的信息来进行映射的。要解决上面的问题,我就是需要重新构一个继承于MappingSource的类。

解决问题

代码如下:


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, 
nullas 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, 
nullas 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。

共有0个回答