e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
978 lines
42 KiB
C#
978 lines
42 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="LinqDataSourceView.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
namespace System.Web.UI.WebControls {
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Collections.Specialized;
|
|
using System.ComponentModel;
|
|
using System.Data.Linq;
|
|
using System.Data.Linq.Mapping;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Web.Compilation;
|
|
using System.Web.Query.Dynamic;
|
|
using System.Web.Resources;
|
|
using System.Security;
|
|
using System.Security.Permissions;
|
|
using DynamicValidatorEventArgs = System.Web.DynamicData.DynamicValidatorEventArgs;
|
|
using DynamicDataSourceOperation = System.Web.DynamicData.DynamicDataSourceOperation;
|
|
|
|
public partial class LinqDataSourceView : ContextDataSourceView {
|
|
private static readonly object EventDeleted = new object();
|
|
private static readonly object EventDeleting = new object();
|
|
private static readonly object EventException = new object();
|
|
private static readonly object EventInserted = new object();
|
|
private static readonly object EventInserting = new object();
|
|
private static readonly object EventUpdated = new object();
|
|
private static readonly object EventUpdating = new object();
|
|
|
|
private HttpContext _context;
|
|
private Type _contextType;
|
|
private string _contextTypeName;
|
|
private LinqDataSource _owner;
|
|
private List<ContextDataSourceContextData> _selectContexts;
|
|
private bool _enableDelete;
|
|
private bool _enableInsert;
|
|
private bool _enableObjectTracking = true;
|
|
private bool _enableUpdate;
|
|
private bool _isNewContext;
|
|
private ILinqToSql _linqToSql;
|
|
private bool _reuseSelectContext;
|
|
private bool _storeOriginalValuesInViewState = true;
|
|
private bool _storeOriginalValues;
|
|
private object _selectResult;
|
|
|
|
public LinqDataSourceView(LinqDataSource owner, string name, HttpContext context)
|
|
: this(owner, name, context, new DynamicQueryableWrapper(), new LinqToSqlWrapper()) {
|
|
}
|
|
|
|
// internal constructor that takes mocks for unit tests.
|
|
internal LinqDataSourceView(LinqDataSource owner, string name, HttpContext context,
|
|
IDynamicQueryable dynamicQueryable, ILinqToSql linqToSql)
|
|
: base(owner, name, context, dynamicQueryable) {
|
|
_context = context;
|
|
_owner = owner;
|
|
_linqToSql = linqToSql;
|
|
}
|
|
|
|
public override bool CanDelete {
|
|
get {
|
|
return EnableDelete;
|
|
}
|
|
}
|
|
|
|
public override bool CanInsert {
|
|
get {
|
|
return EnableInsert;
|
|
}
|
|
}
|
|
|
|
// When AutoPage is false the user should manually page in the Selecting event.
|
|
public override bool CanPage {
|
|
get {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// When AutoPage is false the user must set the total row count in the Selecting event.
|
|
public override bool CanRetrieveTotalRowCount {
|
|
get {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// When AutoSort is false the user should manually sort in the Selecting event.
|
|
public override bool CanSort {
|
|
get {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public override bool CanUpdate {
|
|
get {
|
|
return EnableUpdate;
|
|
}
|
|
}
|
|
|
|
public override Type ContextType {
|
|
[SecuritySafeCritical]
|
|
get {
|
|
if (_contextType == null) {
|
|
string typeName = ContextTypeName;
|
|
if (String.IsNullOrEmpty(typeName)) {
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_ContextTypeNameNotSpecified, _owner.ID));
|
|
}
|
|
try {
|
|
_contextType = BuildManager.GetType(typeName, /*throwOnFail*/true, /*ignoreCase*/true);
|
|
}
|
|
catch (Exception e) {
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_ContextTypeNameNotFound, _owner.ID), e);
|
|
}
|
|
}
|
|
return _contextType;
|
|
}
|
|
}
|
|
|
|
public override string ContextTypeName {
|
|
get {
|
|
return _contextTypeName ?? String.Empty;
|
|
}
|
|
set {
|
|
if (_contextTypeName != value) {
|
|
if (_reuseSelectContext) {
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_ContextTypeNameChanged, _owner.ID));
|
|
}
|
|
_contextTypeName = value;
|
|
_contextType = null;
|
|
OnDataSourceViewChanged(EventArgs.Empty);
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool EnableDelete {
|
|
get {
|
|
return _enableDelete;
|
|
}
|
|
set {
|
|
if (_enableDelete != value) {
|
|
_enableDelete = value;
|
|
OnDataSourceViewChanged(EventArgs.Empty);
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool EnableInsert {
|
|
get {
|
|
return _enableInsert;
|
|
}
|
|
set {
|
|
if (_enableInsert != value) {
|
|
_enableInsert = value;
|
|
OnDataSourceViewChanged(EventArgs.Empty);
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool EnableObjectTracking {
|
|
get {
|
|
return _enableObjectTracking;
|
|
}
|
|
set {
|
|
if (_enableObjectTracking != value) {
|
|
if (_reuseSelectContext) {
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_EnableObjectTrackingChanged, _owner.ID));
|
|
}
|
|
_enableObjectTracking = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool EnableUpdate {
|
|
get {
|
|
return _enableUpdate;
|
|
}
|
|
set {
|
|
if (_enableUpdate != value) {
|
|
_enableUpdate = value;
|
|
OnDataSourceViewChanged(EventArgs.Empty);
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool StoreOriginalValuesInViewState {
|
|
get {
|
|
return _storeOriginalValuesInViewState;
|
|
}
|
|
set {
|
|
if (_storeOriginalValuesInViewState != value) {
|
|
_storeOriginalValuesInViewState = value;
|
|
OnDataSourceViewChanged(EventArgs.Empty);
|
|
}
|
|
}
|
|
}
|
|
|
|
public string TableName {
|
|
get {
|
|
return EntitySetName;
|
|
}
|
|
set {
|
|
if (EntitySetName != value) {
|
|
if (_reuseSelectContext) {
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_TableNameChanged, _owner.ID));
|
|
}
|
|
EntitySetName = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
public event EventHandler<LinqDataSourceStatusEventArgs> ContextCreated {
|
|
add {
|
|
Events.AddHandler(EventContextCreated, value);
|
|
}
|
|
remove {
|
|
Events.RemoveHandler(EventContextCreated, value);
|
|
}
|
|
}
|
|
|
|
public event EventHandler<LinqDataSourceContextEventArgs> ContextCreating {
|
|
add {
|
|
Events.AddHandler(EventContextCreating, value);
|
|
}
|
|
remove {
|
|
Events.RemoveHandler(EventContextCreating, value);
|
|
}
|
|
}
|
|
|
|
public event EventHandler<LinqDataSourceDisposeEventArgs> ContextDisposing {
|
|
add {
|
|
Events.AddHandler(EventContextDisposing, value);
|
|
}
|
|
remove {
|
|
Events.RemoveHandler(EventContextDisposing, value);
|
|
}
|
|
}
|
|
|
|
public event EventHandler<LinqDataSourceStatusEventArgs> Deleted {
|
|
add {
|
|
Events.AddHandler(EventDeleted, value);
|
|
}
|
|
remove {
|
|
Events.RemoveHandler(EventDeleted, value);
|
|
}
|
|
}
|
|
|
|
public event EventHandler<LinqDataSourceDeleteEventArgs> Deleting {
|
|
add {
|
|
Events.AddHandler(EventDeleting, value);
|
|
}
|
|
remove {
|
|
Events.RemoveHandler(EventDeleting, value);
|
|
}
|
|
}
|
|
|
|
internal event EventHandler<DynamicValidatorEventArgs> Exception {
|
|
add {
|
|
Events.AddHandler(EventException, value);
|
|
}
|
|
remove {
|
|
Events.RemoveHandler(EventException, value);
|
|
}
|
|
}
|
|
|
|
public event EventHandler<LinqDataSourceStatusEventArgs> Inserted {
|
|
add {
|
|
Events.AddHandler(EventInserted, value);
|
|
}
|
|
remove {
|
|
Events.RemoveHandler(EventInserted, value);
|
|
}
|
|
}
|
|
|
|
public event EventHandler<LinqDataSourceInsertEventArgs> Inserting {
|
|
add {
|
|
Events.AddHandler(EventInserting, value);
|
|
}
|
|
remove {
|
|
Events.RemoveHandler(EventInserting, value);
|
|
}
|
|
}
|
|
|
|
public event EventHandler<LinqDataSourceStatusEventArgs> Selected {
|
|
add {
|
|
Events.AddHandler(EventSelected, value);
|
|
}
|
|
remove {
|
|
Events.RemoveHandler(EventSelected, value);
|
|
}
|
|
}
|
|
|
|
public event EventHandler<LinqDataSourceSelectEventArgs> Selecting {
|
|
add {
|
|
Events.AddHandler(EventSelecting, value);
|
|
}
|
|
remove {
|
|
Events.RemoveHandler(EventSelecting, value);
|
|
}
|
|
}
|
|
|
|
public event EventHandler<LinqDataSourceStatusEventArgs> Updated {
|
|
add {
|
|
Events.AddHandler(EventUpdated, value);
|
|
}
|
|
remove {
|
|
Events.RemoveHandler(EventUpdated, value);
|
|
}
|
|
}
|
|
|
|
public event EventHandler<LinqDataSourceUpdateEventArgs> Updating {
|
|
add {
|
|
Events.AddHandler(EventUpdating, value);
|
|
}
|
|
remove {
|
|
Events.RemoveHandler(EventUpdating, value);
|
|
}
|
|
}
|
|
|
|
protected virtual object CreateContext(Type contextType) {
|
|
return DataSourceHelper.CreateObjectInstance(contextType);
|
|
}
|
|
|
|
protected override ContextDataSourceContextData CreateContext(DataSourceOperation operation) {
|
|
if (operation == DataSourceOperation.Select) {
|
|
return CreateContextAndTableForSelect();
|
|
}
|
|
return CreateContextAndTableForEdit(operation);
|
|
}
|
|
|
|
private ContextDataSourceContextData CreateContextAndTable(DataSourceOperation operation) {
|
|
ContextDataSourceContextData contextData = null;
|
|
bool eventFired = false;
|
|
try {
|
|
LinqDataSourceContextEventArgs contextEventArgs = new LinqDataSourceContextEventArgs(operation);
|
|
OnContextCreating(contextEventArgs);
|
|
|
|
contextData = new ContextDataSourceContextData(contextEventArgs.ObjectInstance);
|
|
Type contextType = null;
|
|
MemberInfo tableMemberInfo = null;
|
|
if (contextData.Context == null) {
|
|
// construct the context unless accessing a static table for Select.
|
|
contextType = ContextType;
|
|
tableMemberInfo = GetTableMemberInfo(contextType);
|
|
if (tableMemberInfo != null) {
|
|
if (MemberIsStatic(tableMemberInfo)) {
|
|
if (operation != DataSourceOperation.Select) {
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_TableCannotBeStatic, TableName, contextType.Name, _owner.ID));
|
|
}
|
|
}
|
|
else {
|
|
contextData.Context = CreateContext(contextType);
|
|
_isNewContext = true;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// use the manually constructed context.
|
|
tableMemberInfo = GetTableMemberInfo(contextData.Context.GetType());
|
|
}
|
|
|
|
// fetch the table from the context.
|
|
if (tableMemberInfo != null) {
|
|
FieldInfo field = tableMemberInfo as FieldInfo;
|
|
if (field != null) {
|
|
contextData.EntitySet = field.GetValue(contextData.Context);
|
|
}
|
|
PropertyInfo property = tableMemberInfo as PropertyInfo;
|
|
if (property != null) {
|
|
contextData.EntitySet = property.GetValue(contextData.Context, null);
|
|
}
|
|
}
|
|
if (contextData.EntitySet == null) {
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_TableNameNotFound, TableName, contextType.Name, _owner.ID));
|
|
}
|
|
}
|
|
catch (Exception e) {
|
|
eventFired = true;
|
|
LinqDataSourceStatusEventArgs createdEventArgs = new LinqDataSourceStatusEventArgs(e);
|
|
OnContextCreated(createdEventArgs);
|
|
OnException(new DynamicValidatorEventArgs(e, DynamicDataSourceOperation.ContextCreate));
|
|
// CreateContextAndTable will return null if this exception is handled.
|
|
if (!createdEventArgs.ExceptionHandled) {
|
|
throw;
|
|
}
|
|
}
|
|
finally {
|
|
if (!eventFired) {
|
|
// contextData can be null if exception thrown from ContextCreating handler.
|
|
object context = (contextData == null) ? null : contextData.Context;
|
|
LinqDataSourceStatusEventArgs createdEventArgs = new LinqDataSourceStatusEventArgs(context);
|
|
OnContextCreated(createdEventArgs);
|
|
}
|
|
}
|
|
return contextData;
|
|
}
|
|
|
|
private ContextDataSourceContextData CreateContextAndTableForEdit(DataSourceOperation operation) {
|
|
ContextDataSourceContextData contextData = CreateContextAndTable(operation);
|
|
// context data may be null or incomplete if an exception was handled
|
|
if (contextData != null) {
|
|
if (contextData.Context == null) {
|
|
return null;
|
|
}
|
|
if (contextData.EntitySet == null) {
|
|
DisposeContext(contextData.Context);
|
|
return null;
|
|
}
|
|
ValidateContextType(contextData.Context.GetType(), false);
|
|
ValidateTableType(contextData.EntitySet.GetType(), false);
|
|
}
|
|
return contextData;
|
|
}
|
|
|
|
private ContextDataSourceContextData CreateContextAndTableForSelect() {
|
|
_isNewContext = false;
|
|
|
|
if (_selectContexts == null) {
|
|
_selectContexts = new List<ContextDataSourceContextData>();
|
|
}
|
|
else if (_reuseSelectContext && _selectContexts.Count > 0) {
|
|
return _selectContexts[_selectContexts.Count - 1];
|
|
}
|
|
|
|
// context data may be null if an exception was handled
|
|
ContextDataSourceContextData contextData = CreateContextAndTable(DataSourceOperation.Select);
|
|
if (contextData != null) {
|
|
if (contextData.Context != null) {
|
|
ValidateContextType(contextData.Context.GetType(), true);
|
|
}
|
|
if (contextData.EntitySet != null) {
|
|
ValidateTableType(contextData.EntitySet.GetType(), true);
|
|
}
|
|
|
|
_selectContexts.Add(contextData);
|
|
|
|
// context may not be dlinq context or may be null if table was static.
|
|
DataContext dlinqContext = contextData.Context as DataContext;
|
|
if ((dlinqContext != null) && _isNewContext) {
|
|
dlinqContext.ObjectTrackingEnabled = EnableObjectTracking;
|
|
}
|
|
// don't reuse dlinq contexts that cache data or exterior changes will not be reflected.
|
|
_reuseSelectContext = (dlinqContext == null) || !EnableObjectTracking;
|
|
}
|
|
return contextData;
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "object",
|
|
Justification = "Names are consistent with those used in the ObjectDataSource classes")]
|
|
protected virtual void DeleteDataObject(object dataContext, object table, object oldDataObject) {
|
|
_linqToSql.Attach((ITable)table, oldDataObject);
|
|
_linqToSql.Remove((ITable)table, oldDataObject);
|
|
_linqToSql.SubmitChanges((DataContext)dataContext);
|
|
}
|
|
|
|
protected override int DeleteObject(object oldEntity) {
|
|
LinqDataSourceDeleteEventArgs deleteEventArgs = new LinqDataSourceDeleteEventArgs(oldEntity);
|
|
OnDeleting(deleteEventArgs);
|
|
if (deleteEventArgs.Cancel) {
|
|
return -1;
|
|
}
|
|
|
|
LinqDataSourceStatusEventArgs deletedEventArgs = null;
|
|
try {
|
|
DeleteDataObject(Context, EntitySet, deleteEventArgs.OriginalObject);
|
|
}
|
|
catch (Exception e) {
|
|
// allow user to handle dlinq exceptions including OnValidate validation.
|
|
deletedEventArgs = new LinqDataSourceStatusEventArgs(e);
|
|
OnDeleted(deletedEventArgs);
|
|
OnException(new DynamicValidatorEventArgs(e, DynamicDataSourceOperation.Delete));
|
|
if (deletedEventArgs.ExceptionHandled) {
|
|
return -1;
|
|
}
|
|
throw;
|
|
}
|
|
deletedEventArgs = new LinqDataSourceStatusEventArgs(deleteEventArgs.OriginalObject);
|
|
OnDeleted(deletedEventArgs);
|
|
|
|
return 1;
|
|
}
|
|
|
|
protected override void DisposeContext(object dataContext) {
|
|
if (dataContext != null) {
|
|
LinqDataSourceDisposeEventArgs disposingEventArgs = new LinqDataSourceDisposeEventArgs(dataContext);
|
|
OnContextDisposing(disposingEventArgs);
|
|
if (!disposingEventArgs.Cancel) {
|
|
base.DisposeContext(dataContext);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override int ExecuteDelete(IDictionary keys, IDictionary oldValues) {
|
|
ValidateDeleteSupported(keys, oldValues);
|
|
return base.ExecuteDelete(keys, oldValues);
|
|
}
|
|
|
|
protected override int ExecuteInsert(IDictionary values) {
|
|
ValidateInsertSupported(values);
|
|
return base.ExecuteInsert(values);
|
|
}
|
|
|
|
protected override int ExecuteUpdate(IDictionary keys, IDictionary values, IDictionary oldValues) {
|
|
ValidateUpdateSupported(keys, values, oldValues);
|
|
return base.ExecuteUpdate(keys, values, oldValues);
|
|
}
|
|
|
|
protected internal override IEnumerable ExecuteSelect(DataSourceSelectArguments arguments) {
|
|
ClearOriginalValues();
|
|
|
|
QueryContext queryContext = CreateQueryContext(arguments);
|
|
object table = GetSource(queryContext);
|
|
IList result = null;
|
|
|
|
if (_selectResult != null) {
|
|
try {
|
|
IQueryable query = QueryableDataSourceHelper.AsQueryable(_selectResult);
|
|
query = ExecuteQuery(query, queryContext);
|
|
|
|
Type dataObjectType = GetDataObjectType(query.GetType());
|
|
result = query.ToList(dataObjectType);
|
|
|
|
if (_storeOriginalValues) {
|
|
ITable dlinqTable = table as ITable;
|
|
// We can store original values if the type is exact or derived
|
|
if ((dlinqTable != null) && dataObjectType.IsAssignableFrom(EntityType)) {
|
|
StoreOriginalValues(result);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e) {
|
|
result = null;
|
|
LinqDataSourceStatusEventArgs selectedEventArgs = new LinqDataSourceStatusEventArgs(e);
|
|
OnSelected(selectedEventArgs);
|
|
OnException(new DynamicValidatorEventArgs(e, DynamicDataSourceOperation.Select));
|
|
if (!selectedEventArgs.ExceptionHandled) {
|
|
throw;
|
|
}
|
|
}
|
|
finally {
|
|
if (result != null) {
|
|
int totalRowCount = -1; // paging performed, but row count not available.
|
|
if (arguments.RetrieveTotalRowCount) {
|
|
totalRowCount = arguments.TotalRowCount;
|
|
}
|
|
else if (!AutoPage) {
|
|
totalRowCount = result.Count;
|
|
}
|
|
LinqDataSourceStatusEventArgs selectedEventArgs = new LinqDataSourceStatusEventArgs(result, totalRowCount);
|
|
OnSelected(selectedEventArgs);
|
|
}
|
|
}
|
|
// Null out the select context
|
|
Context = null;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
protected override object GetSource(QueryContext context) {
|
|
LinqDataSourceSelectEventArgs selectEventArgs = new LinqDataSourceSelectEventArgs(
|
|
context.Arguments,
|
|
context.WhereParameters,
|
|
context.OrderByParameters,
|
|
context.GroupByParameters,
|
|
context.OrderGroupsByParameters,
|
|
context.SelectParameters);
|
|
|
|
OnSelecting(selectEventArgs);
|
|
if (selectEventArgs.Cancel) {
|
|
return null;
|
|
}
|
|
|
|
_selectResult = selectEventArgs.Result;
|
|
object table = _selectResult;
|
|
|
|
// Original values should only be stored for valid delete and update scenarios.
|
|
_storeOriginalValues = StoreOriginalValuesInViewState && (CanDelete || CanUpdate) &&
|
|
String.IsNullOrEmpty(GroupBy) && String.IsNullOrEmpty(SelectNew);
|
|
|
|
if (_selectResult == null) {
|
|
table = base.GetSource(context);
|
|
_selectResult = table;
|
|
}
|
|
// If the provided select result was not a DLinq table and we need to store
|
|
// original values then we must get the table and create a new data context
|
|
// instance so that we can access the column metadata.
|
|
else if (!(table is ITable) && _storeOriginalValues) {
|
|
table = base.GetSource(context);
|
|
}
|
|
|
|
return table;
|
|
}
|
|
|
|
protected virtual MemberInfo GetTableMemberInfo(Type contextType) {
|
|
string tableName = TableName;
|
|
if (String.IsNullOrEmpty(tableName)) {
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_TableNameNotSpecified, _owner.ID));
|
|
}
|
|
|
|
MemberInfo[] members = contextType.FindMembers(MemberTypes.Field | MemberTypes.Property,
|
|
BindingFlags.Public | BindingFlags.Instance |
|
|
BindingFlags.Static, /*filter*/null, /*filterCriteria*/null);
|
|
|
|
for (int i = 0; i < members.Length; i++) {
|
|
if (String.Equals(members[i].Name, tableName, StringComparison.OrdinalIgnoreCase)) {
|
|
return members[i];
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private ReadOnlyCollection<MetaDataMember> GetTableMetaDataMembers(ITable table, Type dataObjectType) {
|
|
DataContext context = ((ITable)table).Context;
|
|
MetaModel contextMetaData = context.Mapping;
|
|
MetaTable tableMetaData = contextMetaData.GetTable(dataObjectType);
|
|
MetaType rowMetaData = tableMetaData.Model.GetMetaType(dataObjectType);
|
|
return rowMetaData.DataMembers;
|
|
}
|
|
|
|
protected override void HandleValidationErrors(IDictionary<string, Exception> errors, DataSourceOperation operation) {
|
|
LinqDataSourceValidationException exception = new LinqDataSourceValidationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_ValidationFailed,
|
|
EntityType, errors.Values.First().Message),
|
|
errors);
|
|
|
|
bool exceptionHandled = false;
|
|
|
|
switch (operation) {
|
|
case DataSourceOperation.Delete:
|
|
LinqDataSourceDeleteEventArgs deleteEventArgs = new LinqDataSourceDeleteEventArgs(exception);
|
|
OnDeleting(deleteEventArgs);
|
|
OnException(new DynamicValidatorEventArgs(exception, DynamicDataSourceOperation.Delete));
|
|
exceptionHandled = deleteEventArgs.ExceptionHandled;
|
|
break;
|
|
|
|
case DataSourceOperation.Insert:
|
|
LinqDataSourceInsertEventArgs insertEventArgs = new LinqDataSourceInsertEventArgs(exception);
|
|
OnInserting(insertEventArgs);
|
|
OnException(new DynamicValidatorEventArgs(exception, DynamicDataSourceOperation.Insert));
|
|
exceptionHandled = insertEventArgs.ExceptionHandled;
|
|
break;
|
|
case DataSourceOperation.Update:
|
|
// allow user to handle conversion or dlinq property validation exceptions.
|
|
LinqDataSourceUpdateEventArgs updateEventArgs = new LinqDataSourceUpdateEventArgs(exception);
|
|
OnUpdating(updateEventArgs);
|
|
OnException(new DynamicValidatorEventArgs(exception, DynamicDataSourceOperation.Update));
|
|
exceptionHandled = updateEventArgs.ExceptionHandled;
|
|
break;
|
|
}
|
|
|
|
if (!exceptionHandled) {
|
|
throw exception;
|
|
}
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "object",
|
|
Justification = "Names are consistent with those used in the ObjectDataSource classes")]
|
|
protected virtual void InsertDataObject(object dataContext, object table, object newDataObject) {
|
|
_linqToSql.Add((ITable)table, newDataObject);
|
|
_linqToSql.SubmitChanges((DataContext)dataContext);
|
|
}
|
|
|
|
protected override int InsertObject(object newEntity) {
|
|
LinqDataSourceInsertEventArgs insertEventArgs = new LinqDataSourceInsertEventArgs(newEntity);
|
|
OnInserting(insertEventArgs);
|
|
if (insertEventArgs.Cancel) {
|
|
return -1;
|
|
}
|
|
|
|
LinqDataSourceStatusEventArgs insertedEventArgs = null;
|
|
try {
|
|
InsertDataObject(Context, EntitySet, insertEventArgs.NewObject);
|
|
}
|
|
catch (Exception e) {
|
|
// allow user to handle dlinq exceptions including OnValidate validation.
|
|
insertedEventArgs = new LinqDataSourceStatusEventArgs(e);
|
|
OnInserted(insertedEventArgs);
|
|
OnException(new DynamicValidatorEventArgs(e, DynamicDataSourceOperation.Insert));
|
|
if (insertedEventArgs.ExceptionHandled) {
|
|
return -1;
|
|
}
|
|
throw;
|
|
}
|
|
insertedEventArgs = new LinqDataSourceStatusEventArgs(insertEventArgs.NewObject);
|
|
OnInserted(insertedEventArgs);
|
|
|
|
return 1;
|
|
}
|
|
|
|
private static bool MemberIsStatic(MemberInfo member) {
|
|
FieldInfo field = member as FieldInfo;
|
|
if (field != null) {
|
|
return field.IsStatic;
|
|
}
|
|
PropertyInfo property = member as PropertyInfo;
|
|
if (property != null) {
|
|
MethodInfo propertyGetter = property.GetGetMethod();
|
|
return ((propertyGetter != null) && propertyGetter.IsStatic);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#")]
|
|
protected virtual void OnContextCreated(LinqDataSourceStatusEventArgs e) {
|
|
EventHandler<LinqDataSourceStatusEventArgs> handler = (EventHandler<LinqDataSourceStatusEventArgs>)Events[EventContextCreated];
|
|
if (handler != null) {
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#")]
|
|
protected virtual void OnContextCreating(LinqDataSourceContextEventArgs e) {
|
|
EventHandler<LinqDataSourceContextEventArgs> handler = (EventHandler<LinqDataSourceContextEventArgs>)Events[EventContextCreating];
|
|
if (handler != null) {
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#")]
|
|
protected virtual void OnContextDisposing(LinqDataSourceDisposeEventArgs e) {
|
|
EventHandler<LinqDataSourceDisposeEventArgs> handler = (EventHandler<LinqDataSourceDisposeEventArgs>)Events[EventContextDisposing];
|
|
if (handler != null) {
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#")]
|
|
protected virtual void OnDeleted(LinqDataSourceStatusEventArgs e) {
|
|
EventHandler<LinqDataSourceStatusEventArgs> handler =
|
|
(EventHandler<LinqDataSourceStatusEventArgs>)Events[EventDeleted];
|
|
if (handler != null) {
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#")]
|
|
protected virtual void OnDeleting(LinqDataSourceDeleteEventArgs e) {
|
|
EventHandler<LinqDataSourceDeleteEventArgs> handler =
|
|
(EventHandler<LinqDataSourceDeleteEventArgs>)Events[EventDeleting];
|
|
if (handler != null) {
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#")]
|
|
protected virtual void OnException(DynamicValidatorEventArgs e) {
|
|
EventHandler<DynamicValidatorEventArgs> handler = (EventHandler<DynamicValidatorEventArgs>)Events[EventException];
|
|
if (handler != null) {
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#")]
|
|
protected virtual void OnInserted(LinqDataSourceStatusEventArgs e) {
|
|
EventHandler<LinqDataSourceStatusEventArgs> handler =
|
|
(EventHandler<LinqDataSourceStatusEventArgs>)Events[EventInserted];
|
|
if (handler != null) {
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#")]
|
|
protected virtual void OnInserting(LinqDataSourceInsertEventArgs e) {
|
|
EventHandler<LinqDataSourceInsertEventArgs> handler =
|
|
(EventHandler<LinqDataSourceInsertEventArgs>)Events[EventInserting];
|
|
if (handler != null) {
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#")]
|
|
protected virtual void OnSelected(LinqDataSourceStatusEventArgs e) {
|
|
EventHandler<LinqDataSourceStatusEventArgs> handler =
|
|
(EventHandler<LinqDataSourceStatusEventArgs>)Events[EventSelected];
|
|
if (handler != null) {
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#")]
|
|
protected virtual void OnSelecting(LinqDataSourceSelectEventArgs e) {
|
|
EventHandler<LinqDataSourceSelectEventArgs> handler =
|
|
(EventHandler<LinqDataSourceSelectEventArgs>)Events[EventSelecting];
|
|
if (handler != null) {
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#")]
|
|
protected virtual void OnUpdated(LinqDataSourceStatusEventArgs e) {
|
|
EventHandler<LinqDataSourceStatusEventArgs> handler =
|
|
(EventHandler<LinqDataSourceStatusEventArgs>)Events[EventUpdated];
|
|
if (handler != null) {
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#")]
|
|
protected virtual void OnUpdating(LinqDataSourceUpdateEventArgs e) {
|
|
EventHandler<LinqDataSourceUpdateEventArgs> handler =
|
|
(EventHandler<LinqDataSourceUpdateEventArgs>)Events[EventUpdating];
|
|
if (handler != null) {
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
internal void ReleaseSelectContexts() {
|
|
if (_selectContexts != null) {
|
|
foreach (ContextDataSourceContextData contextData in _selectContexts) {
|
|
DisposeContext(contextData.Context);
|
|
}
|
|
}
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters",
|
|
Justification = "Names are consistent with those used in the ObjectDataSource classes")]
|
|
protected virtual void ResetDataObject(object table, object dataObject) {
|
|
// DevDiv Bugs 187705, and 114508: Resetting is no longer necessary because
|
|
// select has it's own context, but this method is kept for compatibility purposes.
|
|
|
|
// no-op
|
|
}
|
|
|
|
public IEnumerable Select(DataSourceSelectArguments arguments) {
|
|
return ExecuteSelect(arguments);
|
|
}
|
|
|
|
private Dictionary<string, Exception> SetDataObjectProperties(object oldDataObject, object newDataObject) {
|
|
Dictionary<string, Exception> validateExceptions = null;
|
|
|
|
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(oldDataObject);
|
|
foreach (PropertyDescriptor property in properties) {
|
|
if (property.PropertyType.IsSerializable && !property.IsReadOnly) {
|
|
object newValue = property.GetValue(newDataObject);
|
|
try {
|
|
property.SetValue(oldDataObject, newValue);
|
|
}
|
|
catch (Exception e) {
|
|
if (validateExceptions == null) {
|
|
validateExceptions = new Dictionary<string, Exception>(StringComparer.OrdinalIgnoreCase);
|
|
}
|
|
validateExceptions[property.Name] = e;
|
|
}
|
|
}
|
|
}
|
|
|
|
return validateExceptions;
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Security", "CA2116:AptcaMethodsShouldOnlyCallAptcaMethods",
|
|
Justification = "System.Data.Linq assembly will be changing to support partial trust.")]
|
|
protected override void StoreOriginalValues(IList results) {
|
|
Type entityType = EntityType;
|
|
IDictionary<string, MetaDataMember> columns = GetTableMetaDataMembers((ITable)EntitySet, entityType).ToDictionary(c => c.Member.Name);
|
|
|
|
StoreOriginalValues(results, p => columns.ContainsKey(p.Name) &&
|
|
(columns[p.Name].IsPrimaryKey ||
|
|
columns[p.Name].IsVersion ||
|
|
(columns[p.Name].UpdateCheck != UpdateCheck.Never)));
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters",
|
|
Justification = "Names are consistent with those used in the ObjectDataSource classes")]
|
|
protected virtual void UpdateDataObject(object dataContext, object table,
|
|
object oldDataObject, object newDataObject) {
|
|
_linqToSql.Attach((ITable)table, oldDataObject);
|
|
Dictionary<string, Exception> validateExceptions = SetDataObjectProperties(oldDataObject, newDataObject);
|
|
|
|
// package up dlinq validation exceptions into single exception.
|
|
if (validateExceptions != null) {
|
|
throw new LinqDataSourceValidationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_ValidationFailed, oldDataObject.GetType(), validateExceptions.Values.First().Message), validateExceptions);
|
|
}
|
|
|
|
_linqToSql.SubmitChanges((DataContext)dataContext);
|
|
}
|
|
|
|
protected override int UpdateObject(object oldEntity, object newEntity) {
|
|
LinqDataSourceUpdateEventArgs updateEventArgs = new LinqDataSourceUpdateEventArgs(oldEntity, newEntity);
|
|
OnUpdating(updateEventArgs);
|
|
if (updateEventArgs.Cancel) {
|
|
return -1;
|
|
}
|
|
|
|
LinqDataSourceStatusEventArgs updatedEventArgs = null;
|
|
try {
|
|
UpdateDataObject(Context, EntitySet, updateEventArgs.OriginalObject, updateEventArgs.NewObject);
|
|
}
|
|
catch (Exception e) {
|
|
ResetDataObject(EntitySet, updateEventArgs.OriginalObject);
|
|
// allow user to handle dlinq exceptions including OnValidate validation.
|
|
updatedEventArgs = new LinqDataSourceStatusEventArgs(e);
|
|
OnUpdated(updatedEventArgs);
|
|
OnException(new DynamicValidatorEventArgs(e, DynamicDataSourceOperation.Update));
|
|
if (updatedEventArgs.ExceptionHandled) {
|
|
return -1;
|
|
}
|
|
throw;
|
|
}
|
|
updatedEventArgs = new LinqDataSourceStatusEventArgs(updateEventArgs.NewObject);
|
|
OnUpdated(updatedEventArgs);
|
|
|
|
return 1;
|
|
}
|
|
|
|
protected virtual void ValidateContextType(Type contextType, bool selecting) {
|
|
if (!selecting && !typeof(DataContext).IsAssignableFrom(contextType)) {
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_InvalidContextType, _owner.ID));
|
|
}
|
|
}
|
|
|
|
protected virtual void ValidateDeleteSupported(IDictionary keys, IDictionary oldValues) {
|
|
if (!CanDelete) {
|
|
throw new NotSupportedException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_DeleteNotSupported, _owner.ID));
|
|
}
|
|
ValidateEditSupported();
|
|
}
|
|
|
|
protected virtual void ValidateEditSupported() {
|
|
if (!String.IsNullOrEmpty(GroupBy)) {
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_GroupByNotSupportedOnEdit, _owner.ID));
|
|
}
|
|
if (!String.IsNullOrEmpty(SelectNew)) {
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_SelectNewNotSupportedOnEdit, _owner.ID));
|
|
}
|
|
}
|
|
|
|
protected virtual void ValidateInsertSupported(IDictionary values) {
|
|
if (!CanInsert) {
|
|
throw new NotSupportedException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_InsertNotSupported, _owner.ID));
|
|
}
|
|
ValidateEditSupported();
|
|
if ((values == null) || (values.Count == 0)) {
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_InsertRequiresValues, _owner.ID));
|
|
}
|
|
}
|
|
|
|
protected virtual void ValidateTableType(Type tableType, bool selecting) {
|
|
if (!selecting) {
|
|
if (!(tableType.IsGenericType && tableType.GetGenericArguments().Length == 1 && typeof(ITable).IsAssignableFrom(tableType))) {
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_InvalidTablePropertyType, _owner.ID));
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual void ValidateUpdateSupported(IDictionary keys, IDictionary values, IDictionary oldValues) {
|
|
if (!CanUpdate) {
|
|
throw new NotSupportedException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_UpdateNotSupported, _owner.ID));
|
|
}
|
|
ValidateEditSupported();
|
|
}
|
|
}
|
|
|
|
}
|
|
|