Imported Upstream version 4.0.0~alpha1

Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
This commit is contained in:
Jo Shields
2015-04-07 09:35:12 +01:00
parent 283343f570
commit 3c1f479b9d
22469 changed files with 2931443 additions and 869343 deletions

View File

@@ -0,0 +1,452 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Reflection;
using System.Linq;
using System.Diagnostics;
namespace System.Data.Linq {
using System.Data.Linq.Mapping;
using System.Data.Linq.Provider;
using System.Diagnostics.CodeAnalysis;
public sealed class ChangeConflictCollection : ICollection<ObjectChangeConflict>, ICollection, IEnumerable<ObjectChangeConflict>, IEnumerable {
private List<ObjectChangeConflict> conflicts;
internal ChangeConflictCollection() {
this.conflicts = new List<ObjectChangeConflict>();
}
/// <summary>
/// The number of conflicts in the collection
/// </summary>
public int Count {
get { return this.conflicts.Count; }
}
public ObjectChangeConflict this[int index] {
get { return this.conflicts[index]; }
}
bool ICollection<ObjectChangeConflict>.IsReadOnly {
get { return true; }
}
void ICollection<ObjectChangeConflict>.Add(ObjectChangeConflict item) {
throw Error.CannotAddChangeConflicts();
}
/// <summary>
/// Removes the specified conflict from the collection.
/// </summary>
/// <param name="item">The conflict to remove</param>
/// <returns></returns>
public bool Remove(ObjectChangeConflict item) {
return this.conflicts.Remove(item);
}
/// <summary>
/// Removes all conflicts from the collection
/// </summary>
public void Clear() {
this.conflicts.Clear();
}
/// <summary>
/// Returns true if the specified conflict is a member of the collection.
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Contains(ObjectChangeConflict item) {
return this.conflicts.Contains(item);
}
public void CopyTo(ObjectChangeConflict[] array, int arrayIndex) {
this.conflicts.CopyTo(array, arrayIndex);
}
/// <summary>
/// Returns the enumerator for the collection.
/// </summary>
/// <returns></returns>
public IEnumerator<ObjectChangeConflict> GetEnumerator() {
return this.conflicts.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return this.conflicts.GetEnumerator();
}
bool ICollection.IsSynchronized {
get { return false; }
}
object ICollection.SyncRoot {
get { return null; }
}
void ICollection.CopyTo(Array array, int index) {
((ICollection)this.conflicts).CopyTo(array, index);
}
/// <summary>
/// Resolves all conflicts in the collection using the specified strategy.
/// </summary>
/// <param name="mode">The strategy to use to resolve the conflicts.</param>
public void ResolveAll(RefreshMode mode) {
this.ResolveAll(mode, true);
}
/// <summary>
/// Resolves all conflicts in the collection using the specified strategy.
/// </summary>
/// <param name="mode">The strategy to use to resolve the conflicts.</param>
/// <param name="autoResolveDeletes">If true conflicts resulting from the modified
/// object no longer existing in the database will be automatically resolved.</param>
public void ResolveAll(RefreshMode mode, bool autoResolveDeletes) {
foreach (ObjectChangeConflict c in this.conflicts) {
if (!c.IsResolved) {
c.Resolve(mode, autoResolveDeletes);
}
}
}
internal void Fill(List<ObjectChangeConflict> conflictList) {
this.conflicts = conflictList;
}
}
internal sealed class ChangeConflictSession {
private DataContext context;
private DataContext refreshContext;
internal ChangeConflictSession(DataContext context) {
this.context = context;
}
internal DataContext Context {
get { return this.context; }
}
internal DataContext RefreshContext {
get {
if (this.refreshContext == null) {
this.refreshContext = this.context.CreateRefreshContext();
}
return this.refreshContext;
}
}
}
/// <summary>
/// Represents an update with one or more optimistic concurrency conflicts.
/// </summary>
public sealed class ObjectChangeConflict {
private ChangeConflictSession session;
private TrackedObject trackedObject;
private bool isResolved;
private ReadOnlyCollection<MemberChangeConflict> memberConflicts;
private object database;
private object original;
private bool? isDeleted;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="session">The session in which the conflicts occurred.</param>
/// <param name="trackedObject">The tracked item in conflict.</param>
internal ObjectChangeConflict(ChangeConflictSession session, TrackedObject trackedObject) {
this.session = session;
this.trackedObject = trackedObject;
this.original = trackedObject.CreateDataCopy(trackedObject.Original);
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="session">The session in which the conflicts occurred.</param>
/// <param name="trackedObject">The tracked item in conflict.</param>
/// <param name="isDeleted">True if the item in conflict no longer exists in the database.</param>
internal ObjectChangeConflict(ChangeConflictSession session, TrackedObject trackedObject, bool isDeleted)
: this(session, trackedObject) {
this.isDeleted = isDeleted;
}
internal ChangeConflictSession Session {
get { return this.session; }
}
internal TrackedObject TrackedObject {
get { return this.trackedObject; }
}
/// <summary>
/// The object in conflict.
/// </summary>
public object Object {
get { return this.trackedObject.Current; }
}
/// <summary>
/// An instance containing the baseline original values used to perform the concurrency check.
/// </summary>
internal object Original {
get { return this.original; }
}
/// <summary>
/// True if the conflicts for this object have already been resovled.
/// </summary>
public bool IsResolved {
get { return this.isResolved; }
}
/// <summary>
/// True if the object in conflict has been deleted from the database.
/// </summary>
public bool IsDeleted {
get {
if (this.isDeleted.HasValue) {
return this.isDeleted.Value;
}
return (this.Database == null);
}
}
/// <summary>
/// An instance containing the most recent values from the database
/// </summary>
internal object Database {
get {
if (this.database == null) {
// use the 'refresh' context to retrieve the current database state
DataContext ctxt = this.session.RefreshContext;
object[] keyValues = CommonDataServices.GetKeyValues(this.trackedObject.Type, this.original);
this.database = ctxt.Services.GetObjectByKey(this.trackedObject.Type, keyValues);
}
return this.database;
}
}
/// <summary>
/// Resolve member conflicts keeping current values and resetting the baseline 'Original' values
/// to match the more recent 'Database' values.
/// </summary>
public void Resolve() {
this.Resolve(RefreshMode.KeepCurrentValues, true);
}
/// <summary>
/// Resolve member conflicts using the mode specified and resetting the baseline 'Original' values
/// to match the more recent 'Database' values.
/// </summary>
/// <param name="refreshMode">The mode that determines how the current values are
/// changed in order to resolve the conflict</param>
public void Resolve(RefreshMode refreshMode) {
this.Resolve(refreshMode, false);
}
/// <summary>
/// Resolve member conflicts using the mode specified and resetting the baseline 'Original' values
/// to match the more recent 'Database' values.
/// </summary>
/// <param name="refreshMode">The mode that determines how the current values are
/// changed in order to resolve the conflict</param>
/// <param name="autoResolveDeletes">If true conflicts resulting from the modified
/// object no longer existing in the database will be automatically resolved.</param>
public void Resolve(RefreshMode refreshMode, bool autoResolveDeletes) {
if (autoResolveDeletes && this.IsDeleted) {
this.ResolveDelete();
}
else {
// We make these calls explicity rather than simply calling
// DataContext.Refresh (which does virtually the same thing)
// since we want to cache the database value read.
if (this.Database == null) {
throw Error.RefreshOfDeletedObject();
}
trackedObject.Refresh(refreshMode, this.Database);
this.isResolved = true;
}
}
/// <summary>
/// Resolve a conflict where we have updated an entity that no longer exists
/// in the database.
/// </summary>
private void ResolveDelete() {
Debug.Assert(this.IsDeleted);
// If the user is attempting to update an entity that no longer exists
// in the database, we first need to [....] the delete into the local cache.
if (!trackedObject.IsDeleted) {
trackedObject.ConvertToDeleted();
}
// As the object have been deleted, it needs to leave the cache
this.Session.Context.Services.RemoveCachedObjectLike(trackedObject.Type, trackedObject.Original);
// Now that our cache is in [....], we accept the changes
this.trackedObject.AcceptChanges();
this.isResolved = true;
}
/// <summary>
/// Returns a collection of all member conflicts that caused the update to fail.
/// </summary>
public ReadOnlyCollection<MemberChangeConflict> MemberConflicts {
get {
if (this.memberConflicts == null) {
var list = new List<MemberChangeConflict>();
if (this.Database != null) {
// determine which members are in conflict
foreach (MetaDataMember metaMember in trackedObject.Type.PersistentDataMembers) {
if (!metaMember.IsAssociation && this.HasMemberConflict(metaMember)) {
list.Add(new MemberChangeConflict(this, metaMember));
}
}
}
this.memberConflicts = list.AsReadOnly();
}
return this.memberConflicts;
}
}
private bool HasMemberConflict(MetaDataMember member) {
object oValue = member.StorageAccessor.GetBoxedValue(this.original);
if (!member.DeclaringType.Type.IsAssignableFrom(this.database.GetType())) {
return false;
}
object dValue = member.StorageAccessor.GetBoxedValue(this.database);
return !this.AreEqual(member, oValue, dValue);
}
private bool AreEqual(MetaDataMember member, object v1, object v2) {
if (v1 == null && v2 == null)
return true;
if (v1 == null || v2 == null)
return false;
if (member.Type == typeof(char[])) {
return this.AreEqual((char[])v1, (char[])v2);
}
else if (member.Type == typeof(byte[])) {
return this.AreEqual((byte[])v1, (byte[])v2);
}
else {
return object.Equals(v1, v2);
}
}
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")]
private bool AreEqual(char[] a1, char[] a2) {
if (a1.Length != a2.Length)
return false;
for (int i = 0, n = a1.Length; i < n; i++) {
if (a1[i] != a2[i])
return false;
}
return true;
}
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")]
private bool AreEqual(byte[] a1, byte[] a2) {
if (a1.Length != a2.Length)
return false;
for (int i = 0, n = a1.Length; i < n; i++) {
if (a1[i] != a2[i])
return false;
}
return true;
}
internal void OnMemberResolved() {
if (!this.IsResolved) {
int nResolved = this.memberConflicts.AsEnumerable().Count(m => m.IsResolved);
if (nResolved == this.memberConflicts.Count) {
this.Resolve(RefreshMode.KeepCurrentValues, false);
}
}
}
}
/// <summary>
/// Represents a single optimistic concurrency member conflict.
/// </summary>
public sealed class MemberChangeConflict {
private ObjectChangeConflict conflict;
private MetaDataMember metaMember;
private object originalValue;
private object databaseValue;
private object currentValue;
bool isResolved;
internal MemberChangeConflict(ObjectChangeConflict conflict, MetaDataMember metaMember) {
this.conflict = conflict;
this.metaMember = metaMember;
this.originalValue = metaMember.StorageAccessor.GetBoxedValue(conflict.Original);
this.databaseValue = metaMember.StorageAccessor.GetBoxedValue(conflict.Database);
this.currentValue = metaMember.StorageAccessor.GetBoxedValue(conflict.TrackedObject.Current);
}
/// <summary>
/// The previous client value.
/// </summary>
public object OriginalValue {
get { return this.originalValue; }
}
/// <summary>
/// The current database value.
/// </summary>
public object DatabaseValue {
get { return this.databaseValue; }
}
/// <summary>
/// The current client value.
/// </summary>
public object CurrentValue {
get { return this.currentValue; }
}
/// <summary>
/// MemberInfo for the member in conflict.
/// </summary>
public MemberInfo Member {
get { return this.metaMember.Member; }
}
/// <summary>
/// Updates the current value to the specified value.
/// </summary>
public void Resolve(object value) {
this.conflict.TrackedObject.RefreshMember(this.metaMember, RefreshMode.OverwriteCurrentValues, value);
this.isResolved = true;
this.conflict.OnMemberResolved();
}
/// <summary>
/// Updates the current value using the specified strategy.
/// </summary>
public void Resolve(RefreshMode refreshMode) {
this.conflict.TrackedObject.RefreshMember(this.metaMember, refreshMode, this.databaseValue);
this.isResolved = true;
this.conflict.OnMemberResolved();
}
/// <summary>
/// True if the value was modified by the client.
/// </summary>
public bool IsModified {
get { return this.conflict.TrackedObject.HasChangedValue(this.metaMember); }
}
/// <summary>
/// True if the member conflict has been resolved.
/// </summary>
public bool IsResolved {
get { return this.isResolved; }
}
}
}

View File

@@ -0,0 +1,420 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Text;
using System.Reflection;
using System.Linq;
using System.Security.Permissions;
using System.Security;
namespace System.Data.Linq {
using System.Data.Linq.Mapping;
using System.Data.Linq.Provider;
using System.Diagnostics.CodeAnalysis;
/// <summary>
/// Controls how inserts, updates and deletes are performed.
/// </summary>
internal abstract class ChangeDirector {
internal abstract int Insert(TrackedObject item);
internal abstract int DynamicInsert(TrackedObject item);
internal abstract void AppendInsertText(TrackedObject item, StringBuilder appendTo);
internal abstract int Update(TrackedObject item);
internal abstract int DynamicUpdate(TrackedObject item);
internal abstract void AppendUpdateText(TrackedObject item, StringBuilder appendTo);
internal abstract int Delete(TrackedObject item);
internal abstract int DynamicDelete(TrackedObject item);
internal abstract void AppendDeleteText(TrackedObject item, StringBuilder appendTo);
internal abstract void RollbackAutoSync();
internal abstract void ClearAutoSyncRollback();
internal static ChangeDirector CreateChangeDirector(DataContext context) {
return new StandardChangeDirector(context);
}
/// <summary>
/// Implementation of ChangeDirector which calls user code if possible
/// and othewise falls back to creating SQL for 'INSERT', 'UPDATE' and 'DELETE'.
/// </summary>
internal class StandardChangeDirector : ChangeDirector {
private enum UpdateType { Insert, Update, Delete };
private enum AutoSyncBehavior { ApplyNewAutoSync, RollbackSavedValues }
DataContext context;
[SuppressMessage("Microsoft.MSInternal", "CA908:AvoidTypesThatRequireJitCompilationInPrecompiledAssemblies", Justification="[....]: FxCop bug Dev10:423110 -- List<KeyValuePair<object, object>> is not supposed to be flagged as a violation.")]
List<KeyValuePair<TrackedObject, object[]>> syncRollbackItems;
internal StandardChangeDirector(DataContext context) {
this.context = context;
}
[SuppressMessage("Microsoft.MSInternal", "CA908:AvoidTypesThatRequireJitCompilationInPrecompiledAssemblies", Justification="[....]: FxCop bug Dev10:423110 -- List<KeyValuePair<object, object>> is not supposed to be flagged as a violation.")]
private List<KeyValuePair<TrackedObject, object[]>> SyncRollbackItems {
get {
if (syncRollbackItems == null) {
syncRollbackItems = new List<KeyValuePair<TrackedObject, object[]>>();
}
return syncRollbackItems;
}
}
internal override int Insert(TrackedObject item) {
if (item.Type.Table.InsertMethod != null) {
try {
item.Type.Table.InsertMethod.Invoke(this.context, new object[] { item.Current });
}
catch (TargetInvocationException tie) {
if (tie.InnerException != null) {
throw tie.InnerException;
}
throw;
}
return 1;
}
else {
return DynamicInsert(item);
}
}
internal override int DynamicInsert(TrackedObject item) {
Expression cmd = this.GetInsertCommand(item);
if (cmd.Type == typeof(int)) {
return (int)this.context.Provider.Execute(cmd).ReturnValue;
}
else {
IEnumerable<object> facts = (IEnumerable<object>)this.context.Provider.Execute(cmd).ReturnValue;
object[] syncResults = (object[])facts.FirstOrDefault();
if (syncResults != null) {
// [....] any auto gen or computed members
AutoSyncMembers(syncResults, item, UpdateType.Insert, AutoSyncBehavior.ApplyNewAutoSync);
return 1;
}
else {
throw Error.InsertAutoSyncFailure();
}
}
}
internal override void AppendInsertText(TrackedObject item, StringBuilder appendTo) {
if (item.Type.Table.InsertMethod != null) {
appendTo.Append(Strings.InsertCallbackComment);
}
else {
Expression cmd = this.GetInsertCommand(item);
appendTo.Append(this.context.Provider.GetQueryText(cmd));
appendTo.AppendLine();
}
}
/// <summary>
/// Update the item, returning 0 if the update fails, 1 if it succeeds.
/// </summary>
internal override int Update(TrackedObject item) {
if (item.Type.Table.UpdateMethod != null) {
// create a copy - don't allow the override to modify our
// internal original values
try {
item.Type.Table.UpdateMethod.Invoke(this.context, new object[] { item.Current });
}
catch (TargetInvocationException tie) {
if (tie.InnerException != null) {
throw tie.InnerException;
}
throw;
}
return 1;
}
else {
return DynamicUpdate(item);
}
}
internal override int DynamicUpdate(TrackedObject item) {
Expression cmd = this.GetUpdateCommand(item);
if (cmd.Type == typeof(int)) {
return (int)this.context.Provider.Execute(cmd).ReturnValue;
}
else {
IEnumerable<object> facts = (IEnumerable<object>)this.context.Provider.Execute(cmd).ReturnValue;
object[] syncResults = (object[])facts.FirstOrDefault();
if (syncResults != null) {
// [....] any auto gen or computed members
AutoSyncMembers(syncResults, item, UpdateType.Update, AutoSyncBehavior.ApplyNewAutoSync);
return 1;
}
else {
return 0;
}
}
}
internal override void AppendUpdateText(TrackedObject item, StringBuilder appendTo) {
if (item.Type.Table.UpdateMethod != null) {
appendTo.Append(Strings.UpdateCallbackComment);
}
else {
Expression cmd = this.GetUpdateCommand(item);
appendTo.Append(this.context.Provider.GetQueryText(cmd));
appendTo.AppendLine();
}
}
internal override int Delete(TrackedObject item) {
if (item.Type.Table.DeleteMethod != null) {
try {
item.Type.Table.DeleteMethod.Invoke(this.context, new object[] { item.Current });
}
catch (TargetInvocationException tie) {
if (tie.InnerException != null) {
throw tie.InnerException;
}
throw;
}
return 1;
}
else {
return DynamicDelete(item);
}
}
internal override int DynamicDelete(TrackedObject item) {
Expression cmd = this.GetDeleteCommand(item);
int ret = (int)this.context.Provider.Execute(cmd).ReturnValue;
if (ret == 0) {
// we don't yet know if the delete failed because the check constaint did not match
// or item was already deleted. Verify the item exists
cmd = this.GetDeleteVerificationCommand(item);
ret = ((int?)this.context.Provider.Execute(cmd).ReturnValue) ?? -1;
}
return ret;
}
internal override void AppendDeleteText(TrackedObject item, StringBuilder appendTo) {
if (item.Type.Table.DeleteMethod != null) {
appendTo.Append(Strings.DeleteCallbackComment);
}
else {
Expression cmd = this.GetDeleteCommand(item);
appendTo.Append(this.context.Provider.GetQueryText(cmd));
appendTo.AppendLine();
}
}
[SuppressMessage("Microsoft.MSInternal", "CA908:AvoidTypesThatRequireJitCompilationInPrecompiledAssemblies", Justification="[....]: FxCop bug Dev10:423110 -- List<KeyValuePair<object, object>> is not supposed to be flagged as a violation.")]
internal override void RollbackAutoSync() {
// Rolls back any AutoSync values that may have been set already
// Those values are no longer valid since the transaction will be rolled back on the server
if (this.syncRollbackItems != null) {
foreach (KeyValuePair<TrackedObject, object[]> rollbackItemPair in this.SyncRollbackItems) {
TrackedObject rollbackItem = rollbackItemPair.Key;
object[] rollbackValues = rollbackItemPair.Value;
AutoSyncMembers(
rollbackValues,
rollbackItem,
rollbackItem.IsNew ? UpdateType.Insert : UpdateType.Update,
AutoSyncBehavior.RollbackSavedValues);
}
}
}
[SuppressMessage("Microsoft.MSInternal", "CA908:AvoidTypesThatRequireJitCompilationInPrecompiledAssemblies", Justification="[....]: FxCop bug Dev10:423110 -- List<KeyValuePair<object, object>> is not supposed to be flagged as a violation.")]
internal override void ClearAutoSyncRollback() {
this.syncRollbackItems = null;
}
private Expression GetInsertCommand(TrackedObject item) {
MetaType mt = item.Type;
// bind to InsertFacts if there are any members to syncronize
List<MetaDataMember> membersToSync = GetAutoSyncMembers(mt, UpdateType.Insert);
ParameterExpression p = Expression.Parameter(item.Type.Table.RowType.Type, "p");
if (membersToSync.Count > 0) {
Expression autoSync = this.CreateAutoSync(membersToSync, p);
LambdaExpression resultSelector = Expression.Lambda(autoSync, p);
return Expression.Call(typeof(DataManipulation), "Insert", new Type[] { item.Type.InheritanceRoot.Type, resultSelector.Body.Type }, Expression.Constant(item.Current), resultSelector);
}
else {
return Expression.Call(typeof(DataManipulation), "Insert", new Type[] { item.Type.InheritanceRoot.Type }, Expression.Constant(item.Current));
}
}
/// <summary>
/// For the meta members specified, create an array initializer for each and bind to
/// an output array.
/// </summary>
private Expression CreateAutoSync(List<MetaDataMember> membersToSync, Expression source) {
System.Diagnostics.Debug.Assert(membersToSync.Count > 0);
int i = 0;
Expression[] initializers = new Expression[membersToSync.Count];
foreach (MetaDataMember mm in membersToSync) {
initializers[i++] = Expression.Convert(this.GetMemberExpression(source, mm.Member), typeof(object));
}
return Expression.NewArrayInit(typeof(object), initializers);
}
private static List<MetaDataMember> GetAutoSyncMembers(MetaType metaType, UpdateType updateType) {
List<MetaDataMember> membersToSync = new List<MetaDataMember>();
foreach (MetaDataMember metaMember in metaType.PersistentDataMembers.OrderBy(m => m.Ordinal)) {
// add all auto generated members for the specified update type to the auto-[....] list
if ((updateType == UpdateType.Insert && metaMember.AutoSync == AutoSync.OnInsert) ||
(updateType == UpdateType.Update && metaMember.AutoSync == AutoSync.OnUpdate) ||
metaMember.AutoSync == AutoSync.Always) {
membersToSync.Add(metaMember);
}
}
return membersToSync;
}
/// <summary>
/// Synchronize the specified item by copying in data from the specified results.
/// Used to [....] members after successful insert or update, but also used to rollback to previous values if a failure
/// occurs on other entities in the same SubmitChanges batch.
/// </summary>
/// <param name="autoSyncBehavior">
/// If AutoSyncBehavior.ApplyNewAutoSync, the current value of the property is saved before the [....] occurs. This is used for normal synchronization after a successful update/insert.
/// Otherwise, the current value is not saved. This is used for rollback operations when something in the SubmitChanges batch failed, rendering the previously-[....]'d values invalid.
/// </param>
[SuppressMessage("Microsoft.MSInternal", "CA908:AvoidTypesThatRequireJitCompilationInPrecompiledAssemblies", Justification="[....]: FxCop bug Dev10:423110 -- List<KeyValuePair<object, object>> is not supposed to be flagged as a violation.")]
private void AutoSyncMembers(object[] syncResults, TrackedObject item, UpdateType updateType, AutoSyncBehavior autoSyncBehavior) {
System.Diagnostics.Debug.Assert(item != null);
System.Diagnostics.Debug.Assert(item.IsNew || item.IsPossiblyModified, "AutoSyncMembers should only be called for new and modified objects.");
object[] syncRollbackValues = null;
if (syncResults != null) {
int idx = 0;
List<MetaDataMember> membersToSync = GetAutoSyncMembers(item.Type, updateType);
System.Diagnostics.Debug.Assert(syncResults.Length == membersToSync.Count);
if (autoSyncBehavior == AutoSyncBehavior.ApplyNewAutoSync) {
syncRollbackValues = new object[syncResults.Length];
}
foreach (MetaDataMember mm in membersToSync) {
object value = syncResults[idx];
object current = item.Current;
MetaAccessor accessor =
(mm.Member is PropertyInfo && ((PropertyInfo)mm.Member).CanWrite)
? mm.MemberAccessor
: mm.StorageAccessor;
if (syncRollbackValues != null) {
syncRollbackValues[idx] = accessor.GetBoxedValue(current);
}
accessor.SetBoxedValue(ref current, DBConvert.ChangeType(value, mm.Type));
idx++;
}
}
if (syncRollbackValues != null) {
this.SyncRollbackItems.Add(new KeyValuePair<TrackedObject, object[]>(item, syncRollbackValues));
}
}
private Expression GetUpdateCommand(TrackedObject tracked) {
object database = tracked.Original;
MetaType rowType = tracked.Type.GetInheritanceType(database.GetType());
MetaType rowTypeRoot = rowType.InheritanceRoot;
ParameterExpression p = Expression.Parameter(rowTypeRoot.Type, "p");
Expression pv = p;
if (rowType != rowTypeRoot) {
pv = Expression.Convert(p, rowType.Type);
}
Expression check = this.GetUpdateCheck(pv, tracked);
if (check != null) {
check = Expression.Lambda(check, p);
}
// bind to out array if there are any members to synchronize
List<MetaDataMember> membersToSync = GetAutoSyncMembers(rowType, UpdateType.Update);
if (membersToSync.Count > 0) {
Expression autoSync = this.CreateAutoSync(membersToSync, pv);
LambdaExpression resultSelector = Expression.Lambda(autoSync, p);
if (check != null) {
return Expression.Call(typeof(DataManipulation), "Update", new Type[] { rowTypeRoot.Type, resultSelector.Body.Type }, Expression.Constant(tracked.Current), check, resultSelector);
}
else {
return Expression.Call(typeof(DataManipulation), "Update", new Type[] { rowTypeRoot.Type, resultSelector.Body.Type }, Expression.Constant(tracked.Current), resultSelector);
}
}
else if (check != null) {
return Expression.Call(typeof(DataManipulation), "Update", new Type[] { rowTypeRoot.Type }, Expression.Constant(tracked.Current), check);
}
else {
return Expression.Call(typeof(DataManipulation), "Update", new Type[] { rowTypeRoot.Type }, Expression.Constant(tracked.Current));
}
}
private Expression GetUpdateCheck(Expression serverItem, TrackedObject tracked) {
MetaType mt = tracked.Type;
if (mt.VersionMember != null) {
return Expression.Equal(
this.GetMemberExpression(serverItem, mt.VersionMember.Member),
this.GetMemberExpression(Expression.Constant(tracked.Current), mt.VersionMember.Member)
);
}
else {
Expression expr = null;
foreach (MetaDataMember mm in mt.PersistentDataMembers) {
if (!mm.IsPrimaryKey) {
UpdateCheck check = mm.UpdateCheck;
if (check == UpdateCheck.Always ||
(check == UpdateCheck.WhenChanged && tracked.HasChangedValue(mm))) {
object memberValue = mm.MemberAccessor.GetBoxedValue(tracked.Original);
Expression eq =
Expression.Equal(
this.GetMemberExpression(serverItem, mm.Member),
Expression.Constant(memberValue, mm.Type)
);
expr = (expr != null) ? Expression.And(expr, eq) : eq;
}
}
}
return expr;
}
}
private Expression GetDeleteCommand(TrackedObject tracked) {
MetaType rowType = tracked.Type;
MetaType rowTypeRoot = rowType.InheritanceRoot;
ParameterExpression p = Expression.Parameter(rowTypeRoot.Type, "p");
Expression pv = p;
if (rowType != rowTypeRoot) {
pv = Expression.Convert(p, rowType.Type);
}
object original = tracked.CreateDataCopy(tracked.Original);
Expression check = this.GetUpdateCheck(pv, tracked);
if (check != null) {
check = Expression.Lambda(check, p);
return Expression.Call(typeof(DataManipulation), "Delete", new Type[] { rowTypeRoot.Type }, Expression.Constant(original), check);
}
else {
return Expression.Call(typeof(DataManipulation), "Delete", new Type[] { rowTypeRoot.Type }, Expression.Constant(original));
}
}
private Expression GetDeleteVerificationCommand(TrackedObject tracked) {
ITable table = this.context.GetTable(tracked.Type.InheritanceRoot.Type);
System.Diagnostics.Debug.Assert(table != null);
ParameterExpression p = Expression.Parameter(table.ElementType, "p");
Expression pred = Expression.Lambda(Expression.Equal(p, Expression.Constant(tracked.Current)), p);
Expression where = Expression.Call(typeof(Queryable), "Where", new Type[] { table.ElementType }, table.Expression, pred);
Expression selector = Expression.Lambda(Expression.Constant(0, typeof(int?)), p);
Expression select = Expression.Call(typeof(Queryable), "Select", new Type[] { table.ElementType, typeof(int?) }, where, selector);
Expression singleOrDefault = Expression.Call(typeof(Queryable), "SingleOrDefault", new Type[] { typeof(int?) }, select);
return singleOrDefault;
}
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")]
private Expression GetMemberExpression(Expression exp, MemberInfo mi) {
FieldInfo fi = mi as FieldInfo;
if (fi != null)
return Expression.Field(exp, fi);
PropertyInfo pi = (PropertyInfo)mi;
return Expression.Property(exp, pi);
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,329 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Common;
using System.Data.Linq.Mapping;
using System.Linq.Expressions;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Transactions;
using System.Data.Linq.Provider;
using System.Diagnostics.CodeAnalysis;
namespace System.Data.Linq {
public sealed class CompiledQuery {
LambdaExpression query;
ICompiledQuery compiled;
MappingSource mappingSource;
private CompiledQuery(LambdaExpression query) {
this.query = query;
}
public LambdaExpression Expression {
get { return this.query; }
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "[....]: Generic types are an important part of Linq APIs and they could not exist without nested generic support.")]
public static Func<TArg0, TResult> Compile<TArg0, TResult>(Expression<Func<TArg0, TResult>> query) where TArg0 : DataContext {
if (query == null) {
Error.ArgumentNull("query");
}
if (UseExpressionCompile(query)) {
return query.Compile();
}
else {
return new CompiledQuery(query).Invoke<TArg0, TResult>;
}
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "[....]: Generic types are an important part of Linq APIs and they could not exist without nested generic support.")]
public static Func<TArg0, TArg1, TResult> Compile<TArg0, TArg1, TResult>(Expression<Func<TArg0, TArg1, TResult>> query) where TArg0 : DataContext {
if (query == null) {
Error.ArgumentNull("query");
}
if (UseExpressionCompile(query)) {
return query.Compile();
}
else {
return new CompiledQuery(query).Invoke<TArg0, TArg1, TResult>;
}
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "[....]: Generic types are an important part of Linq APIs and they could not exist without nested generic support.")]
public static Func<TArg0, TArg1, TArg2, TResult> Compile<TArg0, TArg1, TArg2, TResult>(Expression<Func<TArg0, TArg1, TArg2, TResult>> query) where TArg0 : DataContext {
if (query == null) {
Error.ArgumentNull("query");
}
if (UseExpressionCompile(query)) {
return query.Compile();
}
else {
return new CompiledQuery(query).Invoke<TArg0, TArg1, TArg2, TResult>;
}
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "[....]: Generic types are an important part of Linq APIs and they could not exist without nested generic support.")]
public static Func<TArg0, TArg1, TArg2, TArg3, TResult> Compile<TArg0, TArg1, TArg2, TArg3, TResult>(Expression<Func<TArg0, TArg1, TArg2, TArg3, TResult>> query) where TArg0 : DataContext {
if (query == null) {
Error.ArgumentNull("query");
}
if (UseExpressionCompile(query)) {
return query.Compile();
}
else {
return new CompiledQuery(query).Invoke<TArg0, TArg1, TArg2, TArg3, TResult>;
}
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "[....]: Generic types are an important part of Linq APIs and they could not exist without nested generic support.")]
public static Func<TArg0, TArg1, TArg2, TArg3, TArg4, TResult> Compile<TArg0, TArg1, TArg2, TArg3, TArg4, TResult>(Expression<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TResult>> query) where TArg0 : DataContext {
if (query == null) {
Error.ArgumentNull("query");
}
if (UseExpressionCompile(query)) {
return query.Compile();
}
else {
return new CompiledQuery(query).Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TResult>;
}
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "[....]: Generic types are an important part of Linq APIs and they could not exist without nested generic support.")]
public static Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TResult> Compile<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TResult>(Expression<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TResult>> query) where TArg0 : DataContext {
if (query == null) {
Error.ArgumentNull("query");
}
if (UseExpressionCompile(query)) {
return query.Compile();
}
else {
return new CompiledQuery(query).Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TResult>;
}
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "[....]: Generic types are an important part of Linq APIs and they could not exist without nested generic support.")]
public static Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TResult> Compile<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TResult>(Expression<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TResult>> query) where TArg0 : DataContext {
if (query == null) {
Error.ArgumentNull("query");
}
if (UseExpressionCompile(query)) {
return query.Compile();
}
else {
return new CompiledQuery(query).Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TResult>;
}
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "[....]: Generic types are an important part of Linq APIs and they could not exist without nested generic support.")]
public static Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TResult> Compile<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TResult>(Expression<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TResult>> query) where TArg0 : DataContext {
if (query == null) {
Error.ArgumentNull("query");
}
if (UseExpressionCompile(query)) {
return query.Compile();
}
else {
return new CompiledQuery(query).Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TResult>;
}
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "[....]: Generic types are an important part of Linq APIs and they could not exist without nested generic support.")]
public static Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TResult> Compile<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TResult>(Expression<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TResult>> query) where TArg0 : DataContext {
if (query == null) {
Error.ArgumentNull("query");
}
if (UseExpressionCompile(query)) {
return query.Compile();
}
else {
return new CompiledQuery(query).Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TResult>;
}
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "[....]: Generic types are an important part of Linq APIs and they could not exist without nested generic support.")]
public static Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TResult> Compile<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TResult>(Expression<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TResult>> query) where TArg0 : DataContext {
if (query == null) {
Error.ArgumentNull("query");
}
if (UseExpressionCompile(query)) {
return query.Compile();
}
else {
return new CompiledQuery(query).Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TResult>;
}
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "[....]: Generic types are an important part of Linq APIs and they could not exist without nested generic support.")]
public static Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TResult> Compile<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TResult>(Expression<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TResult>> query) where TArg0 : DataContext {
if (query == null) {
Error.ArgumentNull("query");
}
if (UseExpressionCompile(query)) {
return query.Compile();
}
else {
return new CompiledQuery(query).Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TResult>;
}
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "[....]: Generic types are an important part of Linq APIs and they could not exist without nested generic support.")]
public static Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TResult> Compile<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TResult>(Expression<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TResult>> query) where TArg0 : DataContext {
if (query == null) {
Error.ArgumentNull("query");
}
if (UseExpressionCompile(query)) {
return query.Compile();
}
else {
return new CompiledQuery(query).Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TResult>;
}
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "[....]: Generic types are an important part of Linq APIs and they could not exist without nested generic support.")]
public static Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TResult> Compile<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TResult>(Expression<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TResult>> query) where TArg0 : DataContext {
if (query == null) {
Error.ArgumentNull("query");
}
if (UseExpressionCompile(query)) {
return query.Compile();
}
else {
return new CompiledQuery(query).Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TResult>;
}
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "[....]: Generic types are an important part of Linq APIs and they could not exist without nested generic support.")]
public static Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TResult> Compile<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TResult>(Expression<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TResult>> query) where TArg0 : DataContext {
if (query == null) {
Error.ArgumentNull("query");
}
if (UseExpressionCompile(query)) {
return query.Compile();
}
else {
return new CompiledQuery(query).Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TResult>;
}
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "[....]: Generic types are an important part of Linq APIs and they could not exist without nested generic support.")]
public static Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TArg14, TResult> Compile<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TArg14, TResult>(Expression<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TArg14, TResult>> query) where TArg0 : DataContext {
if (query == null) {
Error.ArgumentNull("query");
}
if (UseExpressionCompile(query)) {
return query.Compile();
}
else {
return new CompiledQuery(query).Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TArg14, TResult>;
}
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "[....]: Generic types are an important part of Linq APIs and they could not exist without nested generic support.")]
public static Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TArg14, TArg15, TResult> Compile<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TArg14, TArg15, TResult>(Expression<Func<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TArg14, TArg15, TResult>> query) where TArg0 : DataContext {
if (query == null) {
Error.ArgumentNull("query");
}
if (UseExpressionCompile(query)) {
return query.Compile();
}
else {
return new CompiledQuery(query).Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TArg14, TArg15, TResult>;
}
}
private static bool UseExpressionCompile(LambdaExpression query) {
return typeof(ITable).IsAssignableFrom(query.Body.Type);
}
private TResult Invoke<TArg0, TResult>(TArg0 arg0) where TArg0 : DataContext {
return (TResult) this.ExecuteQuery(arg0, new object[] {arg0});
}
private TResult Invoke<TArg0, TArg1, TResult>(TArg0 arg0, TArg1 arg1) where TArg0 : DataContext {
return (TResult) this.ExecuteQuery(arg0, new object[] {arg0, arg1});
}
private TResult Invoke<TArg0, TArg1, TArg2, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2) where TArg0 : DataContext {
return (TResult) this.ExecuteQuery(arg0, new object[] {arg0, arg1, arg2});
}
private TResult Invoke<TArg0, TArg1, TArg2, TArg3, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3) where TArg0 : DataContext {
return (TResult) this.ExecuteQuery(arg0, new object[] {arg0, arg1, arg2, arg3});
}
private TResult Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4) where TArg0 : DataContext {
return (TResult) this.ExecuteQuery(arg0, new object[] {arg0, arg1, arg2, arg3, arg4});
}
private TResult Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5) where TArg0 : DataContext {
return (TResult) this.ExecuteQuery(arg0, new object[] {arg0, arg1, arg2, arg3, arg4, arg5});
}
private TResult Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6) where TArg0 : DataContext {
return (TResult) this.ExecuteQuery(arg0, new object[] {arg0, arg1, arg2, arg3, arg4, arg5, arg6});
}
private TResult Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7) where TArg0 : DataContext {
return (TResult) this.ExecuteQuery(arg0, new object[] {arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7});
}
private TResult Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8) where TArg0 : DataContext {
return (TResult) this.ExecuteQuery(arg0, new object[] {arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8});
}
private TResult Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8, TArg9 arg9) where TArg0 : DataContext {
return (TResult) this.ExecuteQuery(arg0, new object[] {arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9});
}
private TResult Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8, TArg9 arg9, TArg10 arg10) where TArg0 : DataContext {
return (TResult) this.ExecuteQuery(arg0, new object[] {arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10});
}
private TResult Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8, TArg9 arg9, TArg10 arg10, TArg11 arg11) where TArg0 : DataContext {
return (TResult) this.ExecuteQuery(arg0, new object[] {arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11});
}
private TResult Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8, TArg9 arg9, TArg10 arg10, TArg11 arg11, TArg12 arg12) where TArg0 : DataContext {
return (TResult) this.ExecuteQuery(arg0, new object[] {arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12});
}
private TResult Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8, TArg9 arg9, TArg10 arg10, TArg11 arg11, TArg12 arg12, TArg13 arg13) where TArg0 : DataContext {
return (TResult) this.ExecuteQuery(arg0, new object[] {arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13});
}
private TResult Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TArg14, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8, TArg9 arg9, TArg10 arg10, TArg11 arg11, TArg12 arg12, TArg13 arg13, TArg14 arg14) where TArg0 : DataContext {
return (TResult) this.ExecuteQuery(arg0, new object[] {arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14});
}
private TResult Invoke<TArg0, TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TArg11, TArg12, TArg13, TArg14, TArg15, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8, TArg9 arg9, TArg10 arg10, TArg11 arg11, TArg12 arg12, TArg13 arg13, TArg14 arg14, TArg15 arg15) where TArg0 : DataContext {
return (TResult) this.ExecuteQuery(arg0, new object[] {arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15});
}
private object ExecuteQuery(DataContext context, object[] args) {
if (context == null) {
throw Error.ArgumentNull("context");
}
if (this.compiled == null) {
lock (this) {
if (this.compiled == null) {
this.compiled = context.Provider.Compile(this.query);
this.mappingSource = context.Mapping.MappingSource;
}
}
}
else {
if (context.Mapping.MappingSource != this.mappingSource)
throw Error.QueryWasCompiledForDifferentMappingSource();
}
return this.compiled.Execute(context.Provider, args).ReturnValue;
}
}
}

View File

@@ -0,0 +1,114 @@
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Data.Linq.Mapping;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace System.Data.Linq.Provider {
internal static class BindingList {
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
internal static IBindingList Create<T>(DataContext context, IEnumerable<T> sequence) {
List<T> list = sequence.ToList();
MetaTable metaTable = context.Services.Model.GetTable(typeof(T));
if (metaTable != null) {
ITable table = context.GetTable(metaTable.RowType.Type);
Type bindingType = typeof(DataBindingList<>).MakeGenericType(metaTable.RowType.Type);
return (IBindingList)Activator.CreateInstance(bindingType,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null,
new object[] { list, table }, null
);
} else {
return new SortableBindingList<T>(list);
}
}
}
internal class DataBindingList<TEntity> : SortableBindingList<TEntity>
where TEntity : class {
private Table<TEntity> data;
private TEntity addNewInstance;
private TEntity cancelNewInstance;
private bool addingNewInstance;
internal DataBindingList(IList<TEntity> sequence, Table<TEntity> data)
: base(sequence != null ? sequence : new List<TEntity>()) {
if (sequence == null) {
throw Error.ArgumentNull("sequence");
}
if (data == null) {
throw Error.ArgumentNull("data");
}
this.data = data;
}
protected override object AddNewCore() {
addingNewInstance = true;
addNewInstance = (TEntity)base.AddNewCore();
return addNewInstance;
}
protected override void InsertItem(int index, TEntity item) {
base.InsertItem(index, item);
if (!addingNewInstance && index >= 0 && index <= Count) {
this.data.InsertOnSubmit(item);
}
}
protected override void RemoveItem(int index) {
if (index >= 0 && index < Count && this[index] == cancelNewInstance) {
cancelNewInstance = null;
}
else {
this.data.DeleteOnSubmit(this[index]);
}
base.RemoveItem(index);
}
protected override void SetItem(int index, TEntity item) {
TEntity removedItem = this[index];
base.SetItem(index, item);
if (index >= 0 && index < Count) {
//Check to see if the user is trying to set an item that is currently being added via AddNew
//If so then the list should not continue the AddNew; but instead add the item
//that is being passed in.
if (removedItem == addNewInstance) {
addNewInstance = null;
addingNewInstance = false;
}
else {
this.data.DeleteOnSubmit(removedItem);
}
this.data.InsertOnSubmit(item);
}
}
protected override void ClearItems() {
this.data.DeleteAllOnSubmit(this.data.ToList());
base.ClearItems();
}
public override void EndNew(int itemIndex) {
if (itemIndex >= 0 && itemIndex < Count && this[itemIndex] == addNewInstance) {
this.data.InsertOnSubmit(addNewInstance);
addNewInstance = null;
addingNewInstance = false;
}
base.EndNew(itemIndex);
}
public override void CancelNew(int itemIndex) {
if (itemIndex >= 0 && itemIndex < Count && this[itemIndex] == addNewInstance) {
cancelNewInstance = addNewInstance;
addNewInstance = null;
addingNewInstance = false;
}
base.CancelNew(itemIndex);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,93 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Linq;
using System.Reflection;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace System.Data.Linq {
using System.Data.Linq.Mapping;
using System.Data.Linq.Provider;
internal sealed class DataQuery<T> : IOrderedQueryable<T>, IQueryProvider, IEnumerable<T>, IOrderedQueryable, IEnumerable, IListSource {
DataContext context;
Expression queryExpression;
private IBindingList cachedList;
public DataQuery(DataContext context, Expression expression) {
this.context = context;
this.queryExpression = expression;
}
Expression IQueryable.Expression {
get { return this.queryExpression; }
}
Type IQueryable.ElementType {
get { return typeof(T); }
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
IQueryable IQueryProvider.CreateQuery(Expression expression) {
if (expression == null)
throw Error.ArgumentNull("expression");
Type eType = System.Data.Linq.SqlClient.TypeSystem.GetElementType(expression.Type);
Type qType = typeof(IQueryable<>).MakeGenericType(eType);
if (!qType.IsAssignableFrom(expression.Type))
throw Error.ExpectedQueryableArgument("expression", qType);
Type dqType = typeof(DataQuery<>).MakeGenericType(eType);
return (IQueryable)Activator.CreateInstance(dqType, new object[] { this.context, expression });
}
IQueryable<S> IQueryProvider.CreateQuery<S>(Expression expression) {
if (expression == null)
throw Error.ArgumentNull("expression");
if (!typeof(IQueryable<S>).IsAssignableFrom(expression.Type))
throw Error.ExpectedQueryableArgument("expression", typeof(IEnumerable<S>));
return new DataQuery<S>(this.context, expression);
}
object IQueryProvider.Execute(Expression expression) {
return this.context.Provider.Execute(expression).ReturnValue;
}
S IQueryProvider.Execute<S>(Expression expression) {
return (S)this.context.Provider.Execute(expression).ReturnValue;
}
IQueryProvider IQueryable.Provider {
get{
return (IQueryProvider)this;
}
}
IEnumerator IEnumerable.GetEnumerator() {
return ((IEnumerable)this.context.Provider.Execute(this.queryExpression).ReturnValue).GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator() {
return ((IEnumerable<T>)this.context.Provider.Execute(this.queryExpression).ReturnValue).GetEnumerator();
}
bool IListSource.ContainsListCollection {
get { return false; }
}
IList IListSource.GetList() {
if (cachedList == null) {
cachedList = GetNewBindingList();
}
return cachedList;
}
internal IBindingList GetNewBindingList() {
return BindingList.Create<T>(this.context, this);
}
public override string ToString() {
return this.context.Provider.GetQueryText(this.queryExpression);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,291 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Linq;
using System.Linq.Expressions;
using System.Collections;
using System.Data.Linq.SqlClient;
using System.Diagnostics.CodeAnalysis;
namespace System.Data.Linq {
sealed public class DataLoadOptions {
bool frozen;
Dictionary<MetaPosition, MemberInfo> includes = new Dictionary<MetaPosition, MemberInfo>();
Dictionary<MetaPosition, LambdaExpression> subqueries = new Dictionary<MetaPosition, LambdaExpression>();
/// <summary>
/// Describe a property that is automatically loaded when the containing instance is loaded
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "[....]: Generic types are an important part of Linq APIs and they could not exist without nested generic support.")]
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "[....]: Need to provide static typing.")]
public void LoadWith<T>(Expression<Func<T, object>> expression) {
if (expression == null) {
throw Error.ArgumentNull("expression");
}
MemberInfo mi = GetLoadWithMemberInfo(expression);
this.Preload(mi);
}
/// <summary>
/// Describe a property that is automatically loaded when the containing instance is loaded
/// </summary>
public void LoadWith(LambdaExpression expression) {
if (expression == null) {
throw Error.ArgumentNull("expression");
}
MemberInfo mi = GetLoadWithMemberInfo(expression);
this.Preload(mi);
}
/// <summary>
/// Place a subquery on the given association.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "[....]: Generic types are an important part of Linq APIs and they could not exist without nested generic support.")]
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "[....]: Need to provide static typing.")]
public void AssociateWith<T>(Expression<Func<T, object>> expression) {
if (expression == null) {
throw Error.ArgumentNull("expression");
}
this.AssociateWithInternal(expression);
}
/// <summary>
/// Place a subquery on the given association.
/// </summary>
public void AssociateWith(LambdaExpression expression) {
if (expression == null) {
throw Error.ArgumentNull("expression");
}
this.AssociateWithInternal(expression);
}
private void AssociateWithInternal(LambdaExpression expression) {
// Strip the cast-to-object.
Expression op = expression.Body;
while (op.NodeType == ExpressionType.Convert || op.NodeType == ExpressionType.ConvertChecked) {
op = ((UnaryExpression)op).Operand;
}
LambdaExpression lambda = Expression.Lambda(op, expression.Parameters.ToArray());
MemberInfo mi = Searcher.MemberInfoOf(lambda);
this.Subquery(mi, lambda);
}
/// <summary>
/// Determines if the member is automatically loaded with its containing instances.
/// </summary>
/// <param name="member">The member this is automatically loaded.</param>
/// <returns>True if the member is automatically loaded.</returns>
internal bool IsPreloaded(MemberInfo member) {
if (member == null) {
throw Error.ArgumentNull("member");
}
return includes.ContainsKey(new MetaPosition(member));
}
/// <summary>
/// Two shapes are equivalent if any of the following are true:
/// (1) They are the same object instance
/// (2) They are both null or empty
/// (3) They contain the same preloaded members
/// </summary>
internal static bool ShapesAreEquivalent(DataLoadOptions ds1, DataLoadOptions ds2) {
bool shapesAreSameOrEmpty = (ds1 == ds2) || ((ds1 == null || ds1.IsEmpty) && (ds2 == null || ds2.IsEmpty));
if (!shapesAreSameOrEmpty) {
if (ds1 == null || ds2 == null || ds1.includes.Count != ds2.includes.Count) {
return false;
}
foreach (MetaPosition metaPosition in ds2.includes.Keys) {
if (!ds1.includes.ContainsKey(metaPosition)) {
return false;
}
}
}
return true;
}
/// <summary>
/// Gets the subquery expression associated with the member.
/// </summary>
/// <param name="member">The member with the subquery.</param>
/// <returns></returns>
internal LambdaExpression GetAssociationSubquery(MemberInfo member) {
if (member == null) {
throw Error.ArgumentNull("member");
}
LambdaExpression expression = null;
subqueries.TryGetValue(new MetaPosition(member), out expression);
return expression;
}
/// <summary>
/// Freeze the shape. Any further attempts to modify the shape will result in
/// an exception.
/// </summary>
internal void Freeze() {
this.frozen = true;
}
/// <summary>
/// Describe a property that is automatically loaded when the containing instance is loaded
/// </summary>
internal void Preload(MemberInfo association) {
if (association == null) {
throw Error.ArgumentNull("association");
}
if (this.frozen) {
throw Error.IncludeNotAllowedAfterFreeze();
}
this.includes.Add(new MetaPosition(association), association);
ValidateTypeGraphAcyclic();
}
/// <summary>
/// Place a subquery on the given association.
/// </summary>
private void Subquery(MemberInfo association, LambdaExpression subquery) {
if (this.frozen) {
throw Error.SubqueryNotAllowedAfterFreeze();
}
subquery = (LambdaExpression)System.Data.Linq.SqlClient.Funcletizer.Funcletize(subquery); // Layering violation.
ValidateSubqueryMember(association);
ValidateSubqueryExpression(subquery);
this.subqueries[new MetaPosition(association)] = subquery;
}
/// <summary>
/// If the lambda specified is of the form p.A, where p is the parameter
/// and A is a member on p, the MemberInfo for A is returned. If
/// the expression is not of this form, an exception is thrown.
/// </summary>
private static MemberInfo GetLoadWithMemberInfo(LambdaExpression lambda)
{
// When the specified member is a value type, there will be a conversion
// to object that we need to strip
Expression body = lambda.Body;
if (body != null && (body.NodeType == ExpressionType.Convert || body.NodeType == ExpressionType.ConvertChecked))
{
body = ((UnaryExpression)body).Operand;
}
MemberExpression mex = body as MemberExpression;
if (mex != null && mex.Expression.NodeType == ExpressionType.Parameter)
{
return mex.Member;
}
else
{
throw Error.InvalidLoadOptionsLoadMemberSpecification();
}
}
private static class Searcher {
static internal MemberInfo MemberInfoOf(LambdaExpression lambda) {
Visitor v = new Visitor();
v.VisitLambda(lambda);
return v.MemberInfo;
}
private class Visitor : System.Data.Linq.SqlClient.ExpressionVisitor {
internal MemberInfo MemberInfo;
internal override Expression VisitMemberAccess(MemberExpression m) {
this.MemberInfo = m.Member;
return base.VisitMemberAccess(m);
}
internal override Expression VisitMethodCall(MethodCallExpression m) {
this.Visit(m.Object);
foreach (Expression arg in m.Arguments) {
this.Visit(arg);
break; // Only follow the extension method 'this'
}
return m;
}
}
}
private void ValidateTypeGraphAcyclic() {
IEnumerable<MemberInfo> edges = this.includes.Values;
int removed = 0;
for (int loop = 0; loop < this.includes.Count; ++loop) {
// Build a list of all edge targets.
HashSet<Type> edgeTargets = new HashSet<Type>();
foreach (MemberInfo edge in edges) {
edgeTargets.Add(GetIncludeTarget(edge));
}
// Remove all edges with sources matching no target.
List<MemberInfo> newEdges = new List<MemberInfo>();
bool someRemoved = false;
foreach (MemberInfo edge in edges) {
if (edgeTargets.Where(et=>et.IsAssignableFrom(edge.DeclaringType) || edge.DeclaringType.IsAssignableFrom(et)).Any()) {
newEdges.Add(edge);
}
else {
++removed;
someRemoved = true;
if (removed == this.includes.Count)
return;
}
}
if (!someRemoved) {
throw Error.IncludeCycleNotAllowed(); // No edges removed, there must be a loop.
}
edges = newEdges;
}
throw new InvalidOperationException("Bug in ValidateTypeGraphAcyclic"); // Getting here means a bug.
}
private static Type GetIncludeTarget(MemberInfo mi) {
Type mt = System.Data.Linq.SqlClient.TypeSystem.GetMemberType(mi);
if (mt.IsGenericType) {
return mt.GetGenericArguments()[0];
}
return mt;
}
private static void ValidateSubqueryMember(MemberInfo mi) {
Type memberType = System.Data.Linq.SqlClient.TypeSystem.GetMemberType(mi);
if (memberType == null) {
throw Error.SubqueryNotSupportedOn(mi);
}
if (!typeof(IEnumerable).IsAssignableFrom(memberType)) {
throw Error.SubqueryNotSupportedOnType(mi.Name, mi.DeclaringType);
}
}
private static void ValidateSubqueryExpression(LambdaExpression subquery) {
if (!typeof(IEnumerable).IsAssignableFrom(subquery.Body.Type)) {
throw Error.SubqueryMustBeSequence();
}
new SubqueryValidator().VisitLambda(subquery);
}
/// <summary>
/// Ensure that the subquery follows the rules for subqueries.
/// </summary>
private class SubqueryValidator : System.Data.Linq.SqlClient.ExpressionVisitor {
bool isTopLevel = true;
internal override Expression VisitMethodCall(MethodCallExpression m) {
bool was = isTopLevel;
try {
if (isTopLevel && !SubqueryRules.IsSupportedTopLevelMethod(m.Method))
throw Error.SubqueryDoesNotSupportOperator(m.Method.Name);
isTopLevel = false;
return base.VisitMethodCall(m);
}
finally {
isTopLevel = was;
}
}
}
/// <summary>
/// Whether there have been LoadOptions specified.
/// </summary>
internal bool IsEmpty {
get { return this.includes.Count == 0 && this.subqueries.Count == 0; }
}
}
}

View File

@@ -0,0 +1,194 @@
using System.Data.Common;
using System.Data.SqlClient;
using System.Linq.Expressions;
using System.IO;
using System.Reflection;
using System.Text;
using System.Runtime.Serialization.Formatters.Binary;
using System.Linq;
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
namespace System.Data.Linq {
public static class DBConvert {
private static Type[] StringArg = new Type[] { typeof(string) };
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "[....]: Generic parameters are required for strong-typing of the return type.")]
public static T ChangeType<T>(object value) {
return (T)ChangeType(value, typeof(T));
}
[SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "[....]: Cast is dependent on node type and casts do not happen unecessarily in a single code path.")]
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")]
public static object ChangeType(object value, Type type) {
if (value == null)
return null;
MethodInfo mi;
Type toType = System.Data.Linq.SqlClient.TypeSystem.GetNonNullableType(type);
Type fromType = value.GetType();
if (toType.IsAssignableFrom(fromType))
return value;
if (toType == typeof(Binary)) {
if (fromType == typeof(byte[])) {
return new Binary((byte[])value);
}
else if (fromType == typeof(Guid)) {
return new Binary(((Guid)value).ToByteArray());
}
else {
BinaryFormatter formatter = new BinaryFormatter();
byte[] streamArray;
using (MemoryStream stream = new MemoryStream()) {
formatter.Serialize(stream, value);
streamArray = stream.ToArray();
}
return new Binary(streamArray);
}
}
else if (toType == typeof(byte[])) {
if (fromType == typeof(Binary)) {
return ((Binary)value).ToArray();
}
else if (fromType == typeof(Guid)) {
return ((Guid)value).ToByteArray();
}
else {
BinaryFormatter formatter = new BinaryFormatter();
byte[] returnValue;
using (MemoryStream stream = new MemoryStream()) {
formatter.Serialize(stream, value);
returnValue = stream.ToArray();
}
return returnValue;
}
}
else if (fromType == typeof(byte[])) {
if (toType == typeof(Guid)) {
return new Guid((byte[])value);
}
else {
BinaryFormatter formatter = new BinaryFormatter();
object returnValue;
using (MemoryStream stream = new MemoryStream((byte[])value)) {
returnValue = ChangeType(formatter.Deserialize(stream), toType);
}
return returnValue;
}
}
else if (fromType == typeof(Binary)) {
if (toType == typeof(Guid)) {
return new Guid(((Binary)value).ToArray());
}
else {
BinaryFormatter formatter = new BinaryFormatter();
using (MemoryStream stream = new MemoryStream(((Binary)value).ToArray(), false)) {
return ChangeType(formatter.Deserialize(stream), toType);
}
}
}
else if (toType.IsEnum) {
if (fromType == typeof(string)) {
string text = ((string)value).Trim();
return Enum.Parse(toType, text);
}
else {
return Enum.ToObject(toType, Convert.ChangeType(value, Enum.GetUnderlyingType(toType), Globalization.CultureInfo.InvariantCulture));
}
}
else if (fromType.IsEnum) {
if (toType == typeof(string)) {
return Enum.GetName(fromType, value);
}
else {
return Convert.ChangeType(Convert.ChangeType(value,
Enum.GetUnderlyingType(fromType),
Globalization.CultureInfo.InvariantCulture),
toType,
Globalization.CultureInfo.InvariantCulture);
}
}
else if (toType == typeof(TimeSpan)) {
if (fromType == typeof(string)) {
return TimeSpan.Parse(value.ToString(), Globalization.CultureInfo.InvariantCulture);
}
else if (fromType == typeof(DateTime)) {
return DateTime.Parse(value.ToString(), Globalization.CultureInfo.InvariantCulture).TimeOfDay;
}
else if (fromType == typeof(DateTimeOffset)) {
return DateTimeOffset.Parse(value.ToString(), Globalization.CultureInfo.InvariantCulture).TimeOfDay;
}
else {
return new TimeSpan((long)Convert.ChangeType(value, typeof(long), Globalization.CultureInfo.InvariantCulture));
}
}
else if (fromType == typeof(TimeSpan)) {
if (toType == typeof(string)) {
return ((TimeSpan)value).ToString("", Globalization.CultureInfo.InvariantCulture);
}
else if (toType == typeof(DateTime)) {
DateTime dt = new DateTime();
return dt.Add((TimeSpan)value);
}
else if (toType == typeof(DateTimeOffset)) {
DateTimeOffset dto = new DateTimeOffset();
return dto.Add((TimeSpan)value);
}
else {
return Convert.ChangeType(((TimeSpan)value).Ticks, toType, Globalization.CultureInfo.InvariantCulture);
}
}
else if (toType == typeof(DateTime) && fromType == typeof(DateTimeOffset)) {
return ((DateTimeOffset)value).DateTime;
}
else if (toType == typeof(DateTimeOffset) && fromType == typeof(DateTime)) {
return new DateTimeOffset((DateTime)value);
}
else if (toType == typeof(string) && !(typeof(IConvertible).IsAssignableFrom(fromType))) {
if (fromType == typeof(char[])) {
return new String((char[])value);
}
else {
return value.ToString();
}
}
else if (fromType == typeof(string)) {
if (toType == typeof(Guid)) {
return new Guid((string)value);
}
else if (toType == typeof(char[])) {
return ((String)value).ToCharArray();
}
else if (toType == typeof(System.Xml.Linq.XDocument) && (string)value == string.Empty) {
return new System.Xml.Linq.XDocument();
}
else if (!(typeof(IConvertible).IsAssignableFrom(toType)) &&
(mi = toType.GetMethod("Parse", BindingFlags.Static | BindingFlags.Public, null, StringArg, null)) != null) {
try {
return SecurityUtils.MethodInfoInvoke(mi, null, new object[] { value });
}
catch (TargetInvocationException t) {
throw t.GetBaseException();
}
}
else {
return Convert.ChangeType(value, toType, Globalization.CultureInfo.InvariantCulture);
}
}
else if (toType.IsGenericType && toType.GetGenericTypeDefinition() == typeof(IQueryable<>)
&& typeof(IEnumerable<>).MakeGenericType(toType.GetGenericArguments()[0]).IsAssignableFrom(fromType)
) {
return Queryable.AsQueryable((IEnumerable)value);
}
else {
try {
return Convert.ChangeType(value, toType, Globalization.CultureInfo.InvariantCulture);
} catch (InvalidCastException) {
throw Error.CouldNotConvert(fromType, toType);
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,108 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Diagnostics.CodeAnalysis;
namespace System.Data.Linq {
internal class EntitySetBindingList<TEntity> : SortableBindingList<TEntity>
where TEntity : class {
private EntitySet<TEntity> data;
private TEntity addNewInstance;
private TEntity cancelNewInstance;
private bool addingNewInstance;
internal EntitySetBindingList(IList<TEntity> sequence, EntitySet<TEntity> data)
: base(sequence) {
if (sequence == null) {
throw Error.ArgumentNull("sequence");
}
if (data == null) {
throw Error.ArgumentNull("data");
}
this.data = data;
}
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")]
private void ThrowEntitySetErrorsIfTypeInappropriate() {
Type type = typeof(TEntity);
if (type.IsAbstract) {
throw Error.EntitySetDataBindingWithAbstractBaseClass(type.Name);
}
if (type.GetConstructor(System.Type.EmptyTypes) == null) {
throw Error.EntitySetDataBindingWithNonPublicDefaultConstructor(type.Name);
}
}
protected override object AddNewCore() {
ThrowEntitySetErrorsIfTypeInappropriate();
addingNewInstance = true;
addNewInstance = (TEntity)base.AddNewCore();
return addNewInstance;
}
protected override void InsertItem(int index, TEntity item) {
base.InsertItem(index, item);
if (!addingNewInstance && index >= 0 && index <= Count) {
this.data.Insert(index, item);
}
}
protected override void RemoveItem(int index) {
if (index >= 0 && index < Count && this[index] == cancelNewInstance) {
cancelNewInstance = null;
}
else {
this.data.Remove(this[index]);
}
base.RemoveItem(index);
}
protected override void SetItem(int index, TEntity item) {
TEntity removedItem = this[index];
base.SetItem(index, item);
if (index >= 0 && index < Count) {
//Check to see if the user is trying to set an item that is currently being added via AddNew
//If so then the list should not continue the AddNew; but instead add the item
//that is being passed in.
if (removedItem == addNewInstance) {
addNewInstance = null;
addingNewInstance = false;
}
else {
this.data.Remove(removedItem);
}
this.data.Insert(index,item);
}
}
protected override void ClearItems() {
this.data.Clear();
base.ClearItems();
}
public override void EndNew(int itemIndex) {
if (itemIndex >= 0 && itemIndex < Count && this[itemIndex] == addNewInstance) {
this.data.Add(addNewInstance);
addNewInstance = null;
addingNewInstance = false;
}
base.EndNew(itemIndex);
}
public override void CancelNew(int itemIndex) {
if (itemIndex >= 0 && itemIndex < Count && this[itemIndex] == addNewInstance) {
cancelNewInstance = addNewInstance;
addNewInstance = null;
addingNewInstance = false;
}
base.CancelNew(itemIndex);
}
}
}

View File

@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Data.Linq.Provider;
using System.Linq;
using System.Diagnostics.CodeAnalysis;
namespace System.Data.Linq {
/// <summary>
/// DLinq-specific custom exception factory.
/// </summary>
[SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable", Justification = "Unknown reason.")]
[SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "Unknown reason.")]
public class ChangeConflictException : Exception {
public ChangeConflictException() { }
public ChangeConflictException(string message) : base(message) { }
public ChangeConflictException(string message, Exception innerException) : base(message, innerException) { }
}
/// <summary>
/// An attempt was made to add an object to the identity cache with a key that is already in use
/// </summary>
[SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable", Justification = "Unknown reason.")]
[SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "Unknown reason.")]
public class DuplicateKeyException : InvalidOperationException {
private object duplicate;
public DuplicateKeyException(object duplicate) {
this.duplicate = duplicate;
}
public DuplicateKeyException(object duplicate, string message)
: base(message) {
this.duplicate = duplicate;
}
public DuplicateKeyException(object duplicate, string message, Exception innerException)
: base(message, innerException) {
this.duplicate = duplicate;
}
/// <summary>
/// The object whose duplicate key caused the exception.
/// </summary>
public object Object {
get {
return duplicate;
}
}
}
/// <summary>
/// An attempt was made to change an FK but the Entity is Loaded
/// </summary>
[SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable", Justification = "Unknown reason.")]
[SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "Unknown reason.")]
public class ForeignKeyReferenceAlreadyHasValueException : InvalidOperationException {
public ForeignKeyReferenceAlreadyHasValueException() { }
public ForeignKeyReferenceAlreadyHasValueException(string message) : base(message) { }
public ForeignKeyReferenceAlreadyHasValueException(string message, Exception innerException) : base(message, innerException) { }
}
}

View File

@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace System.Data.Linq {
/// <summary>
/// The result of executing a query.
/// </summary>
public interface IExecuteResult : IDisposable {
/// <summary>
/// The return value or result of the executed query. This object has the same type as the
/// query expression's Type property.
/// </summary>
object ReturnValue { get; }
/// <summary>
/// Retrieves the nth output parameter. This method is normally used when the query is a mapped
/// function with output parameters.
/// </summary>
/// <param name="parameterIndex"></param>
/// <returns></returns>
object GetParameterValue(int parameterIndex);
}
/// <summary>
/// Interface providing access to a function return value.
/// </summary>
public interface IFunctionResult {
/// <summary>
/// The value.
/// </summary>
object ReturnValue { get; }
}
/// <summary>
/// An interface for representing the result of a mapped function with a single return sequence.
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification="[....]: Meant to represent a database table which is delayed loaded and doesn't provide collection semantics.")]
public interface ISingleResult<T> : IEnumerable<T>, IFunctionResult, IDisposable { }
/// <summary>
/// An interface for representing results of mapped functions or queries with variable return sequences.
/// </summary>
public interface IMultipleResults : IFunctionResult, IDisposable {
/// <summary>
/// Retrieves the next result as a sequence of Type 'TElement'.
/// </summary>
/// <typeparam name="TElement"></typeparam>
/// <returns></returns>
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "[....]: Generic parameters are required for strong-typing of the return type.")]
IEnumerable<TElement> GetResult<TElement>();
}
}

View File

@@ -0,0 +1,14 @@
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Microsoft.MSInternal", "CA900:AptcaAssembliesShouldBeReviewed")]
[assembly: SuppressMessage("Microsoft.MSInternal", "CA905:SystemAndMicrosoftNamespacesRequireApproval", Scope = "namespace", Target = "System.Data.Linq", Justification = "Namespace is approved or will be approved.")]
[assembly: SuppressMessage("Microsoft.MSInternal", "CA905:SystemAndMicrosoftNamespacesRequireApproval", Scope = "namespace", Target = "System.Data.Linq.Mapping", Justification = "Namespace is approved or will be approved.")]
[assembly: SuppressMessage("Microsoft.MSInternal", "CA905:SystemAndMicrosoftNamespacesRequireApproval", Scope = "namespace", Target = "System.Data.Linq.SqlClient", Justification = "Namespace is approved or will be approved.")]
[assembly: SuppressMessage("Microsoft.MSInternal", "CA905:SystemAndMicrosoftNamespacesRequireApproval", Scope = "namespace", Target = "System.Data.Linq.SqlClient.Implementation", Justification = "Namespace is approved or will be approved.")]
[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "System.Data.Linq.SqlClient.Implementation", Justification = "Unknown reason.")]
[assembly: SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", MessageId = "Subquery", Scope = "resource", Target = "System.Data.Linq.resources")]
[assembly: SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", MessageId = "typeof", Scope = "resource", Target = "System.Data.Linq.SqlClient.resources")]
[assembly: SuppressMessage("Microsoft.Performance", "CA1805:DoNotInitializeUnnecessarily", Scope = "member", Target = "System.Data.Linq.Mapping.SR..cctor()", Justification = "External or generated code.")]
[assembly: SuppressMessage("Microsoft.Performance", "CA1805:DoNotInitializeUnnecessarily", Scope = "member", Target = "System.Data.Linq.SqlClient.SR..cctor()", Justification = "External or generated code.")]
[assembly: SuppressMessage("Microsoft.Performance", "CA1805:DoNotInitializeUnnecessarily", Scope = "member", Target = "System.Data.Linq.SR..cctor()", Justification = "External or generated code.")]
[assembly: SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames")]

View File

@@ -0,0 +1,377 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Runtime.CompilerServices;
namespace System.Data.Linq {
using System.Data.Linq.Mapping;
using System.Data.Linq.Provider;
internal abstract class IdentityManager {
internal abstract object InsertLookup(MetaType type, object instance);
internal abstract bool RemoveLike(MetaType type, object instance);
internal abstract object Find(MetaType type, object[] keyValues);
internal abstract object FindLike(MetaType type, object instance);
internal static IdentityManager CreateIdentityManager(bool asReadOnly) {
if (asReadOnly) {
return new ReadOnlyIdentityManager();
}
else {
return new StandardIdentityManager();
}
}
class StandardIdentityManager : IdentityManager {
Dictionary<MetaType, IdentityCache> caches;
IdentityCache currentCache;
MetaType currentType;
internal StandardIdentityManager() {
this.caches = new Dictionary<MetaType, IdentityCache>();
}
internal override object InsertLookup(MetaType type, object instance) {
this.SetCurrent(type);
return this.currentCache.InsertLookup(instance);
}
internal override bool RemoveLike(MetaType type, object instance) {
this.SetCurrent(type);
return this.currentCache.RemoveLike(instance);
}
internal override object Find(MetaType type, object[] keyValues) {
this.SetCurrent(type);
return this.currentCache.Find(keyValues);
}
internal override object FindLike(MetaType type, object instance) {
this.SetCurrent(type);
return this.currentCache.FindLike(instance);
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
private void SetCurrent(MetaType type) {
type = type.InheritanceRoot;
if (this.currentType != type) {
if (!this.caches.TryGetValue(type, out this.currentCache)) {
KeyManager km = GetKeyManager(type);
this.currentCache = (IdentityCache)Activator.CreateInstance(
typeof(IdentityCache<,>).MakeGenericType(type.Type, km.KeyType),
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null,
new object[] { km }, null
);
this.caches.Add(type, this.currentCache);
}
this.currentType = type;
}
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
static KeyManager GetKeyManager(MetaType type) {
int n = type.IdentityMembers.Count;
MetaDataMember mm = type.IdentityMembers[0];
KeyManager km = (KeyManager)Activator.CreateInstance(
typeof(SingleKeyManager<,>).MakeGenericType(type.Type, mm.Type),
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null,
new object[] { mm.StorageAccessor, 0 }, null
);
for (int i = 1; i < n; i++) {
mm = type.IdentityMembers[i];
km = (KeyManager)
Activator.CreateInstance(
typeof(MultiKeyManager<,,>).MakeGenericType(type.Type, mm.Type, km.KeyType),
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null,
new object[] { mm.StorageAccessor, i, km }, null
);
}
return km;
}
#region Nested type definitions
// These types are internal rather than private to work around
// CLR bug #117419 related to type visibility under partial trust
// in nested class scenarios.
internal abstract class KeyManager {
internal abstract Type KeyType { get; }
}
internal abstract class KeyManager<T, K> : KeyManager {
internal abstract K CreateKeyFromInstance(T instance);
internal abstract bool TryCreateKeyFromValues(object[] values, out K k);
internal abstract IEqualityComparer<K> Comparer { get; }
}
internal class SingleKeyManager<T, V> : KeyManager<T, V> {
bool isKeyNullAssignable;
MetaAccessor<T, V> accessor;
int offset;
IEqualityComparer<V> comparer;
internal SingleKeyManager(MetaAccessor<T, V> accessor, int offset) {
this.accessor = accessor;
this.offset = offset;
this.isKeyNullAssignable = System.Data.Linq.SqlClient.TypeSystem.IsNullAssignable(typeof(V));
}
internal override V CreateKeyFromInstance(T instance) {
return this.accessor.GetValue(instance);
}
internal override bool TryCreateKeyFromValues(object[] values, out V v) {
object o = values[this.offset];
if (o == null && !this.isKeyNullAssignable) {
v = default(V);
return false;
}
v = (V)o;
return true;
}
internal override Type KeyType {
get { return typeof(V); }
}
internal override IEqualityComparer<V> Comparer {
get {
if (this.comparer == null) {
this.comparer = EqualityComparer<V>.Default;
}
return this.comparer;
}
}
}
internal class MultiKeyManager<T, V1, V2> : KeyManager<T, MultiKey<V1, V2>> {
MetaAccessor<T, V1> accessor;
int offset;
KeyManager<T, V2> next;
IEqualityComparer<MultiKey<V1, V2>> comparer;
internal MultiKeyManager(MetaAccessor<T, V1> accessor, int offset, KeyManager<T, V2> next) {
this.accessor = accessor;
this.next = next;
this.offset = offset;
}
internal override MultiKey<V1, V2> CreateKeyFromInstance(T instance) {
return new MultiKey<V1, V2>(
this.accessor.GetValue(instance),
this.next.CreateKeyFromInstance(instance)
);
}
internal override bool TryCreateKeyFromValues(object[] values, out MultiKey<V1, V2> k) {
System.Diagnostics.Debug.Assert(this.offset < values.Length, "offset is outside the bounds of the values array");
object o = values[this.offset];
if (o == null && typeof(V1).IsValueType) {
k = default(MultiKey<V1, V2>);
return false;
}
V2 v2;
if (!this.next.TryCreateKeyFromValues(values, out v2)) {
k = default(MultiKey<V1, V2>);
return false;
}
k = new MultiKey<V1, V2>((V1)o, v2);
return true;
}
internal override Type KeyType {
get { return typeof(MultiKey<V1, V2>); }
}
internal override IEqualityComparer<MultiKey<V1, V2>> Comparer {
get {
if (this.comparer == null) {
this.comparer = new MultiKey<V1, V2>.Comparer(EqualityComparer<V1>.Default, next.Comparer);
}
return this.comparer;
}
}
}
internal struct MultiKey<T1, T2> {
T1 value1;
T2 value2;
internal MultiKey(T1 value1, T2 value2) {
this.value1 = value1;
this.value2 = value2;
}
internal class Comparer : IEqualityComparer<MultiKey<T1, T2>>, IEqualityComparer {
IEqualityComparer<T1> comparer1;
IEqualityComparer<T2> comparer2;
internal Comparer(IEqualityComparer<T1> comparer1, IEqualityComparer<T2> comparer2) {
this.comparer1 = comparer1;
this.comparer2 = comparer2;
}
public bool Equals(MultiKey<T1, T2> x, MultiKey<T1, T2> y) {
return this.comparer1.Equals(x.value1, y.value1) &&
this.comparer2.Equals(x.value2, y.value2);
}
public int GetHashCode(MultiKey<T1, T2> x) {
return this.comparer1.GetHashCode(x.value1) ^ this.comparer2.GetHashCode(x.value2);
}
bool IEqualityComparer.Equals(object x, object y) {
return this.Equals((MultiKey<T1, T2>)x, (MultiKey<T1, T2>)y);
}
int IEqualityComparer.GetHashCode(object x) {
return this.GetHashCode((MultiKey<T1, T2>)x);
}
}
}
internal abstract class IdentityCache {
internal abstract object Find(object[] keyValues);
internal abstract object FindLike(object instance);
internal abstract object InsertLookup(object instance);
internal abstract bool RemoveLike(object instance);
}
internal class IdentityCache<T, K> : IdentityCache {
int[] buckets;
Slot[] slots;
int count;
int freeList;
KeyManager<T, K> keyManager;
IEqualityComparer<K> comparer;
public IdentityCache(KeyManager<T, K> keyManager) {
this.keyManager = keyManager;
this.comparer = keyManager.Comparer;
buckets = new int[7];
slots = new Slot[7];
freeList = -1;
}
internal override object InsertLookup(object instance) {
T value = (T)instance;
K key = this.keyManager.CreateKeyFromInstance(value);
Find(key, ref value, true);
return value;
}
internal override bool RemoveLike(object instance) {
T value = (T)instance;
K key = this.keyManager.CreateKeyFromInstance(value);
int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
int bucket = hashCode % buckets.Length;
int last = -1;
for (int i = buckets[bucket] - 1; i >= 0; last = i, i = slots[i].next) {
if (slots[i].hashCode == hashCode && comparer.Equals(slots[i].key, key)) {
if (last < 0) {
buckets[bucket] = slots[i].next + 1;
}
else {
slots[last].next = slots[i].next;
}
slots[i].hashCode = -1;
slots[i].value = default(T);
slots[i].next = freeList;
freeList = i;
return true;
}
}
return false;
}
internal override object Find(object[] keyValues) {
K key;
if (this.keyManager.TryCreateKeyFromValues(keyValues, out key)) {
T value = default(T);
if (Find(key, ref value, false))
return value;
}
return null;
}
internal override object FindLike(object instance) {
T value = (T)instance;
K key = this.keyManager.CreateKeyFromInstance(value);
if (Find(key, ref value, false))
return value;
return null;
}
bool Find(K key, ref T value, bool add) {
int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
for (int i = buckets[hashCode % buckets.Length] - 1; i >= 0; i = slots[i].next) {
if (slots[i].hashCode == hashCode && comparer.Equals(slots[i].key, key)) {
value = slots[i].value;
return true;
}
}
if (add) {
int index;
if (freeList >= 0) {
index = freeList;
freeList = slots[index].next;
}
else {
if (count == slots.Length) Resize();
index = count;
count++;
}
int bucket = hashCode % buckets.Length;
slots[index].hashCode = hashCode;
slots[index].key = key;
slots[index].value = value;
slots[index].next = buckets[bucket] - 1;
buckets[bucket] = index + 1;
}
return false;
}
void Resize() {
int newSize = checked(count * 2 + 1);
int[] newBuckets = new int[newSize];
Slot[] newSlots = new Slot[newSize];
Array.Copy(slots, 0, newSlots, 0, count);
for (int i = 0; i < count; i++) {
int bucket = newSlots[i].hashCode % newSize;
newSlots[i].next = newBuckets[bucket] - 1;
newBuckets[bucket] = i + 1;
}
buckets = newBuckets;
slots = newSlots;
}
internal struct Slot {
internal int hashCode;
internal K key;
internal T value;
internal int next;
}
}
#endregion
}
/// <summary>
/// This is the noop implementation used when object tracking is disabled.
/// </summary>
class ReadOnlyIdentityManager : IdentityManager {
internal ReadOnlyIdentityManager() { }
internal override object InsertLookup(MetaType type, object instance) { return instance; }
internal override bool RemoveLike(MetaType type, object instance) { return false; }
internal override object Find(MetaType type, object[] keyValues) { return null; }
internal override object FindLike(MetaType type, object instance) { return null; }
}
}
}

View File

@@ -0,0 +1,351 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Security.Permissions;
using System.Security;
using System.Runtime.CompilerServices;
namespace System.Data.Linq.Mapping {
using System.Data.Linq.Provider;
using System.Diagnostics.CodeAnalysis;
internal delegate V DGet<T, V>(T t);
internal delegate void DSet<T, V>(T t, V v);
internal delegate void DRSet<T, V>(ref T t, V v);
internal static class FieldAccessor {
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
internal static MetaAccessor Create(Type objectType, FieldInfo fi) {
if (!fi.ReflectedType.IsAssignableFrom(objectType))
throw Error.InvalidFieldInfo(objectType, fi.FieldType, fi);
Delegate dget = null;
Delegate drset = null;
if (!objectType.IsGenericType) {
DynamicMethod mget = new DynamicMethod(
"xget_" + fi.Name,
fi.FieldType,
new Type[] { objectType },
true
);
ILGenerator gen = mget.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldfld, fi);
gen.Emit(OpCodes.Ret);
dget = mget.CreateDelegate(typeof(DGet<,>).MakeGenericType(objectType, fi.FieldType));
DynamicMethod mset = new DynamicMethod(
"xset_" + fi.Name,
typeof(void),
new Type[] { objectType.MakeByRefType(), fi.FieldType },
true
);
gen = mset.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0);
if (!objectType.IsValueType) {
gen.Emit(OpCodes.Ldind_Ref);
}
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Stfld, fi);
gen.Emit(OpCodes.Ret);
drset = mset.CreateDelegate(typeof(DRSet<,>).MakeGenericType(objectType, fi.FieldType));
}
return (MetaAccessor)Activator.CreateInstance(
typeof(Accessor<,>).MakeGenericType(objectType, fi.FieldType),
BindingFlags.Instance | BindingFlags.NonPublic, null,
new object[] { fi, dget, drset }, null
);
}
class Accessor<T, V> : MetaAccessor<T, V> {
DGet<T, V> dget;
DRSet<T, V> drset;
FieldInfo fi;
internal Accessor(FieldInfo fi, DGet<T, V> dget, DRSet<T, V> drset) {
this.fi = fi;
this.dget = dget;
this.drset = drset;
}
public override V GetValue(T instance) {
if (this.dget != null)
return this.dget(instance);
return (V)fi.GetValue(instance);
}
public override void SetValue(ref T instance, V value) {
if (this.drset != null)
this.drset(ref instance, value);
else
this.fi.SetValue(instance, value);
}
}
}
internal static class PropertyAccessor {
internal static MetaAccessor Create(Type objectType, PropertyInfo pi, MetaAccessor storageAccessor) {
Delegate dset = null;
Delegate drset = null;
Type dgetType = typeof(DGet<,>).MakeGenericType(objectType, pi.PropertyType);
MethodInfo getMethod = pi.GetGetMethod(true);
Delegate dget = Delegate.CreateDelegate(dgetType, getMethod, true);
if (dget == null) {
throw Error.CouldNotCreateAccessorToProperty(objectType, pi.PropertyType, pi);
}
if (pi.CanWrite) {
if (!objectType.IsValueType) {
dset = Delegate.CreateDelegate(typeof(DSet<,>).MakeGenericType(objectType, pi.PropertyType), pi.GetSetMethod(true), true);
}
else {
DynamicMethod mset = new DynamicMethod(
"xset_" + pi.Name,
typeof(void),
new Type[] { objectType.MakeByRefType(), pi.PropertyType },
true
);
ILGenerator gen = mset.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0);
if (!objectType.IsValueType) {
gen.Emit(OpCodes.Ldind_Ref);
}
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Call, pi.GetSetMethod(true));
gen.Emit(OpCodes.Ret);
drset = mset.CreateDelegate(typeof(DRSet<,>).MakeGenericType(objectType, pi.PropertyType));
}
}
Type saType = (storageAccessor != null) ? storageAccessor.Type : pi.PropertyType;
return (MetaAccessor)Activator.CreateInstance(
typeof(Accessor<,,>).MakeGenericType(objectType, pi.PropertyType, saType),
BindingFlags.Instance|BindingFlags.NonPublic, null,
new object[] {pi, dget, dset, drset, storageAccessor}, null
);
}
class Accessor<T,V, V2> : MetaAccessor<T,V> where V2 : V {
PropertyInfo pi;
DGet<T, V> dget;
DSet<T, V> dset;
DRSet<T, V> drset;
MetaAccessor<T, V2> storage;
internal Accessor(PropertyInfo pi, DGet<T, V> dget, DSet<T, V> dset, DRSet<T, V> drset, MetaAccessor<T,V2> storage) {
this.pi = pi;
this.dget = dget;
this.dset = dset;
this.drset = drset;
this.storage = storage;
}
public override V GetValue(T instance) {
return this.dget(instance);
}
public override void SetValue(ref T instance, V value) {
if (this.dset != null) {
this.dset(instance, value);
}
else if (this.drset != null) {
this.drset(ref instance, value);
}
else if (this.storage != null) {
this.storage.SetValue(ref instance, (V2)value);
}
else {
throw Error.UnableToAssignValueToReadonlyProperty(this.pi);
}
}
}
}
// deferred type accessors
internal class LinkValueAccessor<T, V> : MetaAccessor<T, V> {
MetaAccessor<T, Link<V>> acc;
internal LinkValueAccessor(MetaAccessor<T, Link<V>> acc) {
this.acc = acc;
}
public override bool HasValue(object instance) {
Link<V> link = this.acc.GetValue((T)instance);
return link.HasValue;
}
public override bool HasAssignedValue(object instance) {
Link<V> link = this.acc.GetValue((T)instance);
return link.HasAssignedValue;
}
public override bool HasLoadedValue(object instance) {
Link<V> link = this.acc.GetValue((T)instance);
return link.HasLoadedValue;
}
public override V GetValue(T instance) {
Link<V> link = this.acc.GetValue(instance);
return link.Value;
}
public override void SetValue(ref T instance, V value) {
this.acc.SetValue(ref instance, new Link<V>(value));
}
}
internal class LinkDefValueAccessor<T, V> : MetaAccessor<T, V> {
MetaAccessor<T, Link<V>> acc;
internal LinkDefValueAccessor(MetaAccessor<T, Link<V>> acc) {
this.acc = acc;
}
public override V GetValue(T instance) {
Link<V> link = this.acc.GetValue(instance);
return link.UnderlyingValue;
}
public override void SetValue(ref T instance, V value) {
this.acc.SetValue(ref instance, new Link<V>(value));
}
}
internal class LinkDefSourceAccessor<T, V> : MetaAccessor<T, IEnumerable<V>> {
MetaAccessor<T, Link<V>> acc;
internal LinkDefSourceAccessor(MetaAccessor<T, Link<V>> acc) {
this.acc = acc;
}
public override IEnumerable<V> GetValue(T instance) {
Link<V> link = this.acc.GetValue(instance);
return (IEnumerable<V>)link.Source;
}
public override void SetValue(ref T instance, IEnumerable<V> value) {
Link<V> link = this.acc.GetValue(instance);
if (link.HasAssignedValue || link.HasLoadedValue) {
throw Error.LinkAlreadyLoaded();
}
this.acc.SetValue(ref instance, new Link<V>(value));
}
}
internal class EntityRefValueAccessor<T, V> : MetaAccessor<T, V> where V : class {
MetaAccessor<T, EntityRef<V>> acc;
internal EntityRefValueAccessor(MetaAccessor<T, EntityRef<V>> acc) {
this.acc = acc;
}
public override V GetValue(T instance) {
EntityRef<V> er = this.acc.GetValue(instance);
return er.Entity;
}
public override void SetValue(ref T instance, V value) {
this.acc.SetValue(ref instance, new EntityRef<V>(value));
}
public override bool HasValue(object instance) {
EntityRef<V> er = this.acc.GetValue((T)instance);
return er.HasValue;
}
public override bool HasAssignedValue(object instance) {
EntityRef<V> er = this.acc.GetValue((T)instance);
return er.HasAssignedValue;
}
public override bool HasLoadedValue(object instance) {
EntityRef<V> er = this.acc.GetValue((T)instance);
return er.HasLoadedValue;
}
}
internal class EntityRefDefValueAccessor<T, V> : MetaAccessor<T, V> where V : class {
MetaAccessor<T, EntityRef<V>> acc;
internal EntityRefDefValueAccessor(MetaAccessor<T, EntityRef<V>> acc) {
this.acc = acc;
}
public override V GetValue(T instance) {
EntityRef<V> er = this.acc.GetValue(instance);
return er.UnderlyingValue;
}
public override void SetValue(ref T instance, V value) {
this.acc.SetValue(ref instance, new EntityRef<V>(value));
}
}
internal class EntityRefDefSourceAccessor<T, V> : MetaAccessor<T, IEnumerable<V>> where V : class {
MetaAccessor<T, EntityRef<V>> acc;
internal EntityRefDefSourceAccessor(MetaAccessor<T, EntityRef<V>> acc) {
this.acc = acc;
}
public override IEnumerable<V> GetValue(T instance) {
EntityRef<V> er = this.acc.GetValue(instance);
return (IEnumerable<V>)er.Source;
}
public override void SetValue(ref T instance, IEnumerable<V> value) {
EntityRef<V> er = this.acc.GetValue(instance);
if (er.HasAssignedValue || er.HasLoadedValue) {
throw Error.EntityRefAlreadyLoaded();
}
this.acc.SetValue(ref instance, new EntityRef<V>(value));
}
}
internal class EntitySetValueAccessor<T, V> : MetaAccessor<T, EntitySet<V>> where V : class {
MetaAccessor<T, EntitySet<V>> acc;
internal EntitySetValueAccessor(MetaAccessor<T, EntitySet<V>> acc) {
this.acc = acc;
}
public override EntitySet<V> GetValue(T instance) {
return this.acc.GetValue(instance);
}
public override void SetValue(ref T instance, EntitySet<V> value) {
EntitySet<V> eset = this.acc.GetValue(instance);
if (eset == null) {
eset = new EntitySet<V>();
this.acc.SetValue(ref instance, eset);
}
eset.Assign(value);
}
public override bool HasValue(object instance) {
EntitySet<V> es = this.acc.GetValue((T)instance);
return es != null && es.HasValues;
}
public override bool HasAssignedValue(object instance) {
EntitySet<V> es = this.acc.GetValue((T)instance);
return es != null && es.HasAssignedValues;
}
public override bool HasLoadedValue(object instance) {
EntitySet<V> es = this.acc.GetValue((T)instance);
return es != null && es.HasLoadedValues;
}
}
internal class EntitySetDefValueAccessor<T, V> : MetaAccessor<T, IEnumerable<V>> where V : class {
MetaAccessor<T, EntitySet<V>> acc;
internal EntitySetDefValueAccessor(MetaAccessor<T, EntitySet<V>> acc) {
this.acc = acc;
}
public override IEnumerable<V> GetValue(T instance) {
EntitySet<V> eset = this.acc.GetValue(instance);
return eset.GetUnderlyingValues();
}
public override void SetValue(ref T instance, IEnumerable<V> value) {
EntitySet<V> eset = this.acc.GetValue(instance);
if (eset == null) {
eset = new EntitySet<V>();
this.acc.SetValue(ref instance, eset);
}
eset.Assign(value);
}
}
internal class EntitySetDefSourceAccessor<T, V> : MetaAccessor<T, IEnumerable<V>> where V : class {
MetaAccessor<T, EntitySet<V>> acc;
internal EntitySetDefSourceAccessor(MetaAccessor<T, EntitySet<V>> acc) {
this.acc = acc;
}
public override IEnumerable<V> GetValue(T instance) {
EntitySet<V> eset = this.acc.GetValue(instance);
return (IEnumerable<V>)eset.Source;
}
public override void SetValue(ref T instance, IEnumerable<V> value) {
EntitySet<V> eset = this.acc.GetValue(instance);
if (eset == null) {
eset = new EntitySet<V>();
this.acc.SetValue(ref instance, eset);
}
eset.SetSource(value);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,274 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics.CodeAnalysis;
namespace System.Data.Linq.Mapping {
/// <summary>
/// Attribute placed on a method mapped to a User Defined Function.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public sealed class FunctionAttribute : Attribute {
string name;
bool isComposable;
public FunctionAttribute() {
}
public string Name {
get { return this.name; }
set { this.name = value; }
}
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Composable", Justification="Spelling is correct.")]
public bool IsComposable {
get { return this.isComposable; }
set { this.isComposable = value; }
}
}
/// <summary>
/// This attribute is applied to functions returning multiple result types,
/// to declare the possible result types returned from the function. For
/// inheritance types, only the root type of the inheritance hierarchy need
/// be specified.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public sealed class ResultTypeAttribute : Attribute {
Type type;
public ResultTypeAttribute(Type type) {
this.type = type;
}
[SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "The contexts in which this is available are fairly specific.")]
public Type Type {
get { return this.type; }
}
}
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = false)]
public sealed class ParameterAttribute : Attribute {
string name;
string dbType;
public ParameterAttribute() {
}
public string Name {
get { return this.name; }
set { this.name = value; }
}
[SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db", Justification = "Conforms to legacy spelling.")]
public string DbType {
get { return this.dbType; }
set { this.dbType = value; }
}
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class DatabaseAttribute : Attribute {
string name;
public DatabaseAttribute() {
}
public string Name {
get { return this.name; }
set { this.name = value; }
}
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public sealed class TableAttribute : Attribute {
string name;
public TableAttribute() {
}
public string Name {
get { return this.name; }
set { this.name = value; }
}
}
/// <summary>
/// Class attribute used to describe an inheritance hierarchy to be mapped.
/// For example,
///
/// [Table(Name = "People")]
/// [InheritanceMapping(Code = "P", Type = typeof(Person), IsDefault=true)]
/// [InheritanceMapping(Code = "C", Type = typeof(Customer))]
/// [InheritanceMapping(Code = "E", Type = typeof(Employee))]
/// class Person { ... }
///
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple=true, Inherited = false)]
public sealed class InheritanceMappingAttribute : Attribute {
private object code;
private Type type;
private bool isDefault;
/// <summary>
/// Discriminator value in store column for this type.
/// </summary>
public object Code {
get { return this.code; }
set { this.code = value; }
}
/// <summary>
/// Type to instantiate when Key is matched.
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification="The contexts in which this is available are fairly specific.")]
public Type Type {
get { return this.type; }
set { this.type = value; }
}
/// <summary>
/// If discriminator value in store column is unrecognized then instantiate this type.
/// </summary>
public bool IsDefault {
get { return this.isDefault; }
set { this.isDefault = value; }
}
}
public abstract class DataAttribute : Attribute {
string name;
string storage;
protected DataAttribute() { }
public string Name {
get { return this.name; }
set { name = value; }
}
public string Storage {
get { return this.storage; }
set { this.storage = value; }
}
}
public enum UpdateCheck {
Always,
Never,
WhenChanged
}
/// <summary>
/// Used to specify for during insert and update operations when
/// a data member should be read back after the operation completes.
/// </summary>
public enum AutoSync {
Default = 0, // Automatically choose
Always = 1,
Never = 2,
OnInsert = 3,
OnUpdate = 4
}
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
public sealed class ColumnAttribute : DataAttribute {
string dbtype;
string expression;
bool isPrimaryKey;
bool isDBGenerated;
bool isVersion;
bool isDiscriminator;
bool canBeNull = true;
UpdateCheck check;
AutoSync autoSync = AutoSync.Default;
bool canBeNullSet = false;
public ColumnAttribute() {
check = UpdateCheck.Always;
}
[SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db", Justification="Conforms to legacy spelling.")]
public string DbType {
get { return this.dbtype; }
set { this.dbtype = value; }
}
public string Expression {
get { return this.expression; }
set { this.expression = value; }
}
public bool IsPrimaryKey {
get { return this.isPrimaryKey; }
set { this.isPrimaryKey = value; }
}
[SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db", Justification = "Conforms to legacy spelling.")]
public bool IsDbGenerated {
get { return this.isDBGenerated; }
set { this.isDBGenerated = value; }
}
public bool IsVersion {
get { return this.isVersion; }
set { this.isVersion = value; }
}
public UpdateCheck UpdateCheck {
get { return this.check; }
set { this.check = value; }
}
public AutoSync AutoSync {
get { return this.autoSync; }
set { this.autoSync = value; }
}
public bool IsDiscriminator {
get { return this.isDiscriminator; }
set { isDiscriminator = value; }
}
public bool CanBeNull {
get {return this.canBeNull;}
set {
this.canBeNullSet = true;
this.canBeNull = value;
}
}
internal bool CanBeNullSet {
get {return this.canBeNullSet;}
}
}
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
public sealed class AssociationAttribute : DataAttribute {
string thisKey;
string otherKey;
bool isUnique;
bool isForeignKey;
bool deleteOnNull;
string deleteRule;
public AssociationAttribute() { }
public string ThisKey {
get { return this.thisKey; }
set { this.thisKey = value; }
}
public string OtherKey {
get { return this.otherKey; }
set { this.otherKey = value; }
}
public bool IsUnique {
get { return this.isUnique; }
set { this.isUnique = value; }
}
public bool IsForeignKey {
get { return this.isForeignKey; }
set { this.isForeignKey = value; }
}
public string DeleteRule {
get { return this.deleteRule; }
set { this.deleteRule = value; }
}
public bool DeleteOnNull {
get { return this.deleteOnNull; }
set { this.deleteOnNull = value; }
}
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class ProviderAttribute : Attribute {
Type providerType;
public ProviderAttribute() {
}
public ProviderAttribute(Type type) {
this.providerType = type;
}
[SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "The contexts in which this is available are fairly specific.")]
public Type Type {
get { return this.providerType; }
}
}
}

Some files were not shown because too many files have changed in this diff Show More