Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DLinq / Dlinq / Mapping / AttributedMetaModel.cs / 1599186 / AttributedMetaModel.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Linq;
using System.Data.Linq.Provider;
using System.Data.Linq.SqlClient;
using System.Threading;
using LinqToSqlShared.Mapping;
using System.Runtime.CompilerServices;
namespace System.Data.Linq.Mapping {
internal static class MethodFinder {
internal static MethodInfo FindMethod(Type type, string name, BindingFlags flags, Type[] argTypes) {
return FindMethod(type, name, flags, argTypes, true);
}
internal static MethodInfo FindMethod(Type type, string name, BindingFlags flags, Type[] argTypes, bool allowInherit) {
for (; type != typeof(object); type = type.BaseType) {
MethodInfo mi = type.GetMethod(name, flags | BindingFlags.DeclaredOnly, null, argTypes, null);
if (mi != null || !allowInherit) {
return mi;
}
}
return null;
}
}
internal static class InheritanceBaseFinder {
internal static MetaType FindBase(MetaType derivedType) {
if (derivedType.Type == typeof(object)) {
return null;
}
var clrType = derivedType.Type; // start
var rootClrType = derivedType.InheritanceRoot.Type; // end
var metaTable = derivedType.Table;
MetaType metaType = null;
while (true) {
if (clrType == typeof(object) || clrType == rootClrType) {
return null;
}
clrType = clrType.BaseType;
metaType = derivedType.InheritanceRoot.GetInheritanceType(clrType);
if (metaType != null) {
return metaType;
}
}
}
}
internal class AttributedMetaModel : MetaModel {
ReaderWriterLock @lock = new ReaderWriterLock();
MappingSource mappingSource;
Type contextType;
Type providerType;
Dictionary metaTypes;
Dictionary metaTables;
ReadOnlyCollection staticTables;
Dictionary metaFunctions;
string dbName;
bool initStaticTables;
bool initFunctions;
internal AttributedMetaModel(MappingSource mappingSource, Type contextType) {
this.mappingSource = mappingSource;
this.contextType = contextType;
this.metaTypes = new Dictionary();
this.metaTables = new Dictionary();
this.metaFunctions = new Dictionary();
// Provider type
ProviderAttribute[] attrs = (ProviderAttribute[])this.contextType.GetCustomAttributes(typeof(ProviderAttribute), true);
if (attrs != null && attrs.Length == 1) { // Provider attribute is !AllowMultiple
this.providerType = attrs[0].Type;
} else {
this.providerType = typeof(SqlProvider);
}
// Database name
DatabaseAttribute[] das = (DatabaseAttribute[])this.contextType.GetCustomAttributes(typeof(DatabaseAttribute), false);
this.dbName = (das != null && das.Length > 0) ? das[0].Name : this.contextType.Name;
}
public override MappingSource MappingSource {
get { return this.mappingSource; }
}
public override Type ContextType {
get { return this.contextType; }
}
public override string DatabaseName {
get { return this.dbName; }
}
public override Type ProviderType {
get { return this.providerType; }
}
public override IEnumerable GetTables() {
this.InitStaticTables();
if (this.staticTables.Count > 0) {
return this.staticTables;
}
else {
@lock.AcquireReaderLock(Timeout.Infinite);
try {
return this.metaTables.Values.Where(x => x != null).Distinct();
}
finally {
@lock.ReleaseReaderLock();
}
}
}
#region Initialization
private void InitStaticTables() {
if (!this.initStaticTables) {
@lock.AcquireWriterLock(Timeout.Infinite);
try {
if (!this.initStaticTables) {
HashSet tables = new HashSet();
for (Type type = this.contextType; type != typeof(DataContext); type = type.BaseType) {
FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
foreach (FieldInfo fi in fields) {
Type ft = fi.FieldType;
if (ft.IsGenericType && ft.GetGenericTypeDefinition() == typeof(Table<>)) {
Type rowType = ft.GetGenericArguments()[0];
tables.Add(this.GetTableNoLocks(rowType));
}
}
PropertyInfo[] props = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
foreach (PropertyInfo pi in props) {
Type pt = pi.PropertyType;
if (pt.IsGenericType && pt.GetGenericTypeDefinition() == typeof(Table<>)) {
Type rowType = pt.GetGenericArguments()[0];
tables.Add(this.GetTableNoLocks(rowType));
}
}
}
this.staticTables = new List(tables).AsReadOnly();
this.initStaticTables = true;
}
}
finally {
@lock.ReleaseWriterLock();
}
}
}
private void InitFunctions() {
if (!this.initFunctions) {
@lock.AcquireWriterLock(Timeout.Infinite);
try {
if (!this.initFunctions) {
if (this.contextType != typeof(DataContext)) {
for (Type type = this.contextType; type != typeof(DataContext); type = type.BaseType) {
foreach (MethodInfo mi in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) {
if (IsUserFunction(mi)) {
if (mi.IsGenericMethodDefinition) {
// Added this constraint because XML mapping model didn't support mapping sprocs to generic method.
// The attribute mapping model was, however, able to support it. This check is for parity between
// the two models.
throw Error.InvalidUseOfGenericMethodAsMappedFunction(mi.Name);
}
MetaPosition mp = new MetaPosition(mi);
if (!this.metaFunctions.ContainsKey(mp)) {
MetaFunction metaFunction = new AttributedMetaFunction(this, mi);
this.metaFunctions.Add(mp, metaFunction);
// pre-set all known function result types into metaType map
foreach (MetaType rt in metaFunction.ResultRowTypes) {
foreach (MetaType it in rt.InheritanceTypes) {
if (!this.metaTypes.ContainsKey(it.Type)) {
this.metaTypes.Add(it.Type, it);
}
}
}
}
}
}
}
}
this.initFunctions = true;
}
}
finally {
@lock.ReleaseWriterLock();
}
}
}
private static bool IsUserFunction(MethodInfo mi) {
return Attribute.GetCustomAttribute(mi, typeof(FunctionAttribute), false) != null;
}
#endregion
public override MetaTable GetTable(Type rowType) {
if (rowType == null) {
throw Error.ArgumentNull("rowType");
}
MetaTable table;
@lock.AcquireReaderLock(Timeout.Infinite);
try {
if (this.metaTables.TryGetValue(rowType, out table)) {
return table;
}
}
finally {
@lock.ReleaseReaderLock();
}
@lock.AcquireWriterLock(Timeout.Infinite);
try {
table = this.GetTableNoLocks(rowType);
}
finally {
@lock.ReleaseWriterLock();
}
return table;
}
internal MetaTable GetTableNoLocks(Type rowType) {
MetaTable table;
if (!this.metaTables.TryGetValue(rowType, out table)) {
Type root = GetRoot(rowType) ?? rowType;
TableAttribute[] attrs = (TableAttribute[])root.GetCustomAttributes(typeof(TableAttribute), true);
if (attrs.Length == 0) {
this.metaTables.Add(rowType, null);
}
else {
if (!this.metaTables.TryGetValue(root, out table)) {
table = new AttributedMetaTable(this, attrs[0], root);
foreach (MetaType mt in table.RowType.InheritanceTypes) {
this.metaTables.Add(mt.Type, table);
}
}
// catch case of derived type that is not part of inheritance
if (table.RowType.GetInheritanceType(rowType) == null) {
this.metaTables.Add(rowType, null);
return null;
}
}
}
return table;
}
private static Type GetRoot(Type derivedType) {
while (derivedType != null && derivedType != typeof(object)) {
TableAttribute[] attrs = (TableAttribute[])derivedType.GetCustomAttributes(typeof(TableAttribute), false);
if (attrs.Length > 0)
return derivedType;
derivedType = derivedType.BaseType;
}
return null;
}
public override MetaType GetMetaType(Type type) {
if (type == null) {
throw Error.ArgumentNull("type");
}
MetaType mtype = null;
@lock.AcquireReaderLock(Timeout.Infinite);
try {
if (this.metaTypes.TryGetValue(type, out mtype)) {
return mtype;
}
}
finally {
@lock.ReleaseReaderLock();
}
// Attributed meta model allows us to learn about tables we did not
// statically know about
MetaTable tab = this.GetTable(type);
if (tab != null) {
return tab.RowType.GetInheritanceType(type);
}
this.InitFunctions();
@lock.AcquireWriterLock(Timeout.Infinite);
try {
if (!this.metaTypes.TryGetValue(type, out mtype)) {
mtype = new UnmappedType(this, type);
this.metaTypes.Add(type, mtype);
}
}
finally {
@lock.ReleaseWriterLock();
}
return mtype;
}
public override MetaFunction GetFunction(MethodInfo method) {
if (method == null) {
throw Error.ArgumentNull("method");
}
this.InitFunctions();
MetaFunction function = null;
this.metaFunctions.TryGetValue(new MetaPosition(method), out function);
return function;
}
public override IEnumerable GetFunctions() {
this.InitFunctions();
return this.metaFunctions.Values.ToList().AsReadOnly();
}
}
internal sealed class AttributedMetaTable : MetaTable {
AttributedMetaModel model;
string tableName;
MetaType rowType;
bool hasMethods;
MethodInfo insertMethod;
MethodInfo updateMethod;
MethodInfo deleteMethod;
internal AttributedMetaTable(AttributedMetaModel model, TableAttribute attr, Type rowType) {
this.model = model;
this.tableName = string.IsNullOrEmpty(attr.Name) ? rowType.Name : attr.Name;
this.rowType = new AttributedRootType(model, this, rowType);
}
public override MetaModel Model {
get { return this.model; }
}
public override string TableName {
get { return this.tableName; }
}
public override MetaType RowType {
get { return this.rowType; }
}
public override MethodInfo InsertMethod {
get {
this.InitMethods();
return this.insertMethod;
}
}
public override MethodInfo UpdateMethod {
get {
this.InitMethods();
return this.updateMethod;
}
}
public override MethodInfo DeleteMethod {
get {
this.InitMethods();
return this.deleteMethod;
}
}
private void InitMethods() {
if (!this.hasMethods) {
this.insertMethod = MethodFinder.FindMethod(
this.model.ContextType,
"Insert" + rowType.Name,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
new Type[] { rowType.Type }
);
this.updateMethod = MethodFinder.FindMethod(
this.model.ContextType,
"Update" + rowType.Name,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
new Type[] { rowType.Type }
);
this.deleteMethod = MethodFinder.FindMethod(
this.model.ContextType,
"Delete" + rowType.Name,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
new Type[] { rowType.Type }
);
this.hasMethods = true;
}
}
}
internal sealed class AttributedRootType : AttributedMetaType {
Dictionary types;
Dictionary