我想知道是否有可能动态设置linq类的表映射:
[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.[Comfort 0601$Contact]")]
public partial class Contact : INotifyPropertyChanging, INotifyPropertyChanged
{
...
我想要动态或编程地改变这个的原因是因为我正在使用的数据库是由Navision创建的。在那里,这些表有一个前缀,即这些表所属的公司名称。因此,我希望能够改变前缀。
[global::System.Data.Linq.Mapping.TableAttribute(Name = "dbo.["+SPResources.Database.Company+"$Contact]")]
怀特公司:
public const string Company = "Comfort 0601";
我已经尝试过了,但是只有当我将Company声明为常量时才有效。
公司之间的表结构相同。只是名字&内容改变。
我希望有人能给一些建议。我也不确定这是否可能。
考虑添加表前缀的正确解决方案是使用SQL Server 2005(或更新版本),然后为每个所需的前缀创建一个db-user,并将每个db-user的默认模式从"dbo"更改为唯一的模式
另一个解决方案是扩展现有的DataContext,使其能够在运行时"纠正"MappingSource:
[Table] // Look no name
public class DbRecord
{
[Column(IsPrimaryKey=true)]
public long Id { get; set; }
}
CustomDataContext.UpdateCustomTable(typeof(DbRecord), "DbTable");
using (CustomDataContext dc = new CustomDataContext(dbConnection))
{
Table<DbRecord> dbTable = dc.GetTable<DbRecord>();
var query = from item in dbTable;
}
这是自定义的DataContext(我想一个人可以很容易地改变它添加一个前缀到现有的表名)(替换字典与ConcurrentDictionary,如果在多线程环境):
public class CustomDataContext : DataContext
{
static CustomMappingSource _sharedMappingSource = new CustomMappingSource();
public static void UpdateCustomTable(Type rowType, string tableName)
{
_sharedMappingSource.UpdateCustomTable(rowType, tableName);
}
public CustomDataContext(System.Data.IDbConnection connection) : base(connection, _sharedMappingSource) { }
public CustomDataContext(string fileOrServerOrConnection) : base(fileOrServerOrConnection, _sharedMappingSource) { }
}
internal class CustomMappingSource : MappingSource
{
AttributeMappingSource mapping = new AttributeMappingSource();
Dictionary<Type, string> _customTableNames = new Dictionary<Type, string>();
public void UpdateCustomTable(Type rowType, string tableName)
{
if (string.IsNullOrEmpty(tableName))
throw new ArgumentNullException("TableName");
_customTableNames[rowType] = tableName;
}
protected override MetaModel CreateModel(Type dataContextType)
{
MetaModel oldmodel = mapping.GetModel(dataContextType);
CustomMetaModel newmodel = new CustomMetaModel(oldmodel, _customTableNames);
return newmodel;
}
}
internal class CustomMetaModel : MetaModel
{
MetaModel _orgmodel;
Dictionary<Type, MetaTable> _customtables = new Dictionary<Type, MetaTable>();
Dictionary<Type, string> _tableNames = new Dictionary<Type, string>();
public CustomMetaModel(MetaModel orgmodel, Dictionary<Type, string> tableNames)
{
_orgmodel = orgmodel;
_tableNames = tableNames;
}
public override MetaType GetMetaType(Type type)
{
MetaTable metaTable;
if (_customtables.TryGetValue(type, out metaTable))
return metaTable.RowType;
else
return _orgmodel.GetMetaType(type);
}
public override MetaTable GetTable(Type rowType)
{
MetaTable customMetaTable;
if (_customtables.TryGetValue(rowType, out customMetaTable))
return customMetaTable;
if (_tableNames.ContainsKey(rowType))
{
MetaTable orgtable = _orgmodel.GetTable(rowType);
MetaType orgrowtype = orgtable.RowType;
CustomMetaType newRowType = new CustomMetaType(orgrowtype, this);
_customtables.Add(rowType, new CustomMetaTable(orgtable, this, newRowType, _tableNames[rowType]));
newRowType.MetaTable = _customtables[rowType];
return newRowType.MetaTable;
}
return _orgmodel.GetTable(rowType);
}
#region MetaModel Forwards
public override Type ContextType { get { return _orgmodel.ContextType; } }
public override string DatabaseName { get { return _orgmodel.DatabaseName; } }
public override MappingSource MappingSource { get { return _orgmodel.MappingSource; } }
public override Type ProviderType { get { return _orgmodel.ProviderType; } }
public override MetaFunction GetFunction(System.Reflection.MethodInfo method) { return _orgmodel.GetFunction(method); }
public override IEnumerable<MetaFunction> GetFunctions() { return _orgmodel.GetFunctions(); }
public override IEnumerable<MetaTable> GetTables() { return _orgmodel.GetTables(); }
#endregion
}
internal class CustomMetaTable : MetaTable
{
MetaTable _orgtable;
MetaModel _metamodel;
MetaType _rowtype;
string _tableName;
public CustomMetaTable(MetaTable orgtable, MetaModel metamodel, MetaType rowtype, string tableName)
{
_orgtable = orgtable;
_metamodel = metamodel;
_rowtype = rowtype;
_tableName = tableName;
}
public override MetaModel Model { get { return _metamodel; } }
public override MetaType RowType { get { return _rowtype; } }
public override string TableName { get { return _tableName; } }
#region MetaTable Forwards
public override System.Reflection.MethodInfo DeleteMethod { get { return _orgtable.DeleteMethod; } }
public override System.Reflection.MethodInfo InsertMethod { get { return _orgtable.InsertMethod; } }
public override System.Reflection.MethodInfo UpdateMethod { get { return _orgtable.UpdateMethod; } }
#endregion
}
internal class CustomMetaType : MetaType
{
MetaType _orgtype;
MetaModel _metamodel;
public MetaTable MetaTable { get; set; }
public CustomMetaType(MetaType orgtype, MetaModel metamodel)
{
_orgtype = orgtype;
_metamodel = metamodel;
}
public override MetaTable Table { get { return MetaTable; } }
public override MetaModel Model { get { return _metamodel; } }
#region MetaType Forwards
public override System.Collections.ObjectModel.ReadOnlyCollection<MetaAssociation> Associations { get { return _orgtype.Associations; } }
public override bool CanInstantiate { get { return _orgtype.CanInstantiate; } }
public override System.Collections.ObjectModel.ReadOnlyCollection<MetaDataMember> DataMembers { get { return _orgtype.DataMembers; } }
public override MetaDataMember DBGeneratedIdentityMember { get { return _orgtype.DBGeneratedIdentityMember; } }
public override System.Collections.ObjectModel.ReadOnlyCollection<MetaType> DerivedTypes { get { return _orgtype.DerivedTypes; } }
public override MetaDataMember Discriminator { get { return _orgtype.Discriminator; } }
public override bool HasAnyLoadMethod { get { return _orgtype.HasAnyLoadMethod; } }
public override bool HasAnyValidateMethod { get { return _orgtype.HasAnyValidateMethod; } }
public override bool HasInheritance { get { return _orgtype.HasInheritance; } }
public override bool HasInheritanceCode { get { return _orgtype.HasInheritanceCode; } }
public override bool HasUpdateCheck { get { return _orgtype.HasUpdateCheck; } }
public override System.Collections.ObjectModel.ReadOnlyCollection<MetaDataMember> IdentityMembers { get { return _orgtype.IdentityMembers; } }
public override MetaType InheritanceBase { get { return _orgtype.InheritanceBase; } }
public override object InheritanceCode { get { return _orgtype.InheritanceCode; } }
public override MetaType InheritanceDefault { get { return _orgtype.InheritanceDefault; } }
public override MetaType InheritanceRoot { get { return _orgtype.InheritanceRoot; } }
public override System.Collections.ObjectModel.ReadOnlyCollection<MetaType> InheritanceTypes { get { return _orgtype.InheritanceTypes; } }
public override bool IsEntity { get { return _orgtype.IsEntity; } }
public override bool IsInheritanceDefault { get { return _orgtype.IsInheritanceDefault; } }
public override string Name { get { return _orgtype.Name; } }
public override System.Reflection.MethodInfo OnLoadedMethod { get { return _orgtype.OnLoadedMethod; } }
public override System.Reflection.MethodInfo OnValidateMethod { get { return _orgtype.OnValidateMethod; } }
public override System.Collections.ObjectModel.ReadOnlyCollection<MetaDataMember> PersistentDataMembers { get { return _orgtype.PersistentDataMembers; } }
public override Type Type { get { return _orgtype.Type; } }
public override MetaDataMember VersionMember { get { return _orgtype.VersionMember; } }
public override MetaDataMember GetDataMember(System.Reflection.MemberInfo member) { return _orgtype.GetDataMember(member); }
public override MetaType GetInheritanceType(Type type) { return _orgtype.GetInheritanceType(type); }
public override MetaType GetTypeForInheritanceCode(object code) { return _orgtype.GetTypeForInheritanceCode(code); }
#endregion
}
Brian和Gert的答案是这个问题的可能解决方案。但是在运行时更改映射是不可能的(正如Brian提到的)。
随着项目的进展,我们决定如果我们需要另一个公司名称(这意味着该构建是针对不同的客户的),我们将重新构建项目。这个决定使得下面的解决方案成为可能:
我们注释掉了Visual Studio生成的原始映射:
//[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.[Comfort 0601$Contact]")]
public partial class Contact : INotifyPropertyChanging, INotifyPropertyChanged
{
...
因为每个Linq类都有自己的部分类,所以我们在自己的类的顶部添加了修改后的映射:
[global::System.Data.Linq.Mapping.TableAttribute(Name = "dbo.["+SPResources.Database.Company+"$Contact]")]
public partial class Contact
{
我们的公司将在哪里:
public const string Company = "Comfort 0601";
如果需要为不同的公司重新构建,我们只需更改company变量。
注意:这只有在你不改变你的*时才能正常工作。如果你这样做,VS会自动撤销你的更改。
编辑:随着时间的流逝,我开始更多地研究实体框架,我找到了一个更具体和合适的解决方案:http://www.codeproject.com/Articles/421643/How-to-Use-MVC-Net-on-the-Dynamics-NAV-Database-St
您可以使用SQLMetal为每个实体定制生成代码。您不能在运行时动态地应用属性,因此这将是最好的选择。
如果你工作代码优先,你可以使用流畅的映射,你可以使用ToTable()
方法在运行时配置数据库表(参见更改数据库表名)。例如,在DbContext派生的OnModelCreating()
重写中:
string company = "Comfort 0601";
modelBuilder.Entity<Contact>().ToTable(company + "Contact");
modelBuilder.Entity<....
modelBuilder.Entity<....
您可以从配置文件中获取公司名称