Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / xsp / System / Web / Extensions / ui / webcontrols / LinqDataSourceView.cs / 2 / LinqDataSourceView.cs
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//-----------------------------------------------------------------------------
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.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Compilation;
using System.Web.Query.Dynamic;
using System.Web.Resources;
using DynamicValidatorEventArgs = System.Web.DynamicData.DynamicValidatorEventArgs;
using DynamicDataSourceOperation = System.Web.DynamicData.DynamicDataSourceOperation;
[AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
public class LinqDataSourceView : DataSourceView, IStateManager {
private class LinqDataSourceAutoGeneratedWhere {
public LinqDataSourceAutoGeneratedWhere(string Where, IDictionary WhereParameters) {
this.Where = Where;
this.WhereParameters = WhereParameters;
}
public string Where { get; set; }
public IDictionary WhereParameters;
}
// This regular expression verifies that parameter names are set to valid identifiers. This validation
// needs to match the parser's identifier validation as done in the default block of NextToken().
private static readonly string _identifierPattern =
@"^\s*[\p{Lu}\p{Ll}\p{Lt}\p{Lm}\p{Lo}\p{Nl}_]" + // first character
@"[\p{Lu}\p{Ll}\p{Lt}\p{Lm}\p{Lo}\p{Nl}\p{Nd}\p{Pc}\p{Mn}\p{Mc}\p{Cf}_]*"; // remaining characters
private static readonly Regex _identifierRegex = new Regex(_identifierPattern + @"\s*$");
private static readonly Regex _autoGenerateOrderByRegex = new Regex(_identifierPattern +
@"(\s+(asc|ascending|desc|descending))?\s*$", RegexOptions.IgnoreCase); // order operators
private static readonly object EventContextCreated = new object();
private static readonly object EventContextCreating = new object();
private static readonly object EventContextDisposing = new object();
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 EventSelected = new object();
private static readonly object EventSelecting = new object();
private static readonly object EventUpdated = new object();
private static readonly object EventUpdating = new object();
private HttpContext _context;
private LinqDataSource _owner;
private bool _tracking;
private bool _autoGenerateOrderByClause = false;
private bool _autoGenerateWhereClause = false;
private bool _autoPage = true;
private bool _autoSort = true;
private string _contextTypeName;
private Type _contextType;
private List _selectContexts;
private ParameterCollection _deleteParameters;
private IDynamicQueryable _dynamicQueryable;
private bool _enableDelete = false;
private bool _enableInsert = false;
private bool _enableObjectTracking = true;
private bool _enableUpdate = false;
private string _groupBy;
private ParameterCollection _groupByParameters;
private ParameterCollection _insertParameters;
private ILinqToSql _linqToSql;
private string _orderBy;
private ParameterCollection _orderByParameters;
private string _orderGroupsBy;
private ParameterCollection _orderGroupsByParameters;
// using Hashtable for original values so that ObjectStateFormatter will serialize it properly in ViewState.
private Hashtable _originalValues;
private bool _reuseSelectContext;
private string _selectNew;
private ParameterCollection _selectNewParameters;
private bool _storeOriginalValuesInViewState = true;
private string _tableName;
private ParameterCollection _updateParameters;
private string _where;
private ParameterCollection _whereParameters;
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) {
_owner = owner;
_context = context;
_dynamicQueryable = dynamicQueryable;
_linqToSql = linqToSql;
}
public bool AutoGenerateOrderByClause {
get {
return _autoGenerateOrderByClause;
}
set {
if (_autoGenerateOrderByClause != value) {
_autoGenerateOrderByClause = value;
OnDataSourceViewChanged(EventArgs.Empty);
}
}
}
public bool AutoGenerateWhereClause {
get {
return _autoGenerateWhereClause;
}
set {
if (_autoGenerateWhereClause != value) {
_autoGenerateWhereClause = value;
OnDataSourceViewChanged(EventArgs.Empty);
}
}
}
public bool AutoPage {
get {
return _autoPage;
}
set {
if (_autoPage != value) {
_autoPage = value;
OnDataSourceViewChanged(EventArgs.Empty);
}
}
}
public bool AutoSort {
get {
return _autoSort;
}
set {
if (_autoSort != value) {
_autoSort = value;
OnDataSourceViewChanged(EventArgs.Empty);
}
}
}
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;
}
}
protected internal virtual Type ContextType {
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 virtual 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 ParameterCollection DeleteParameters {
get {
if (_deleteParameters == null) {
_deleteParameters = new ParameterCollection();
}
return _deleteParameters;
}
}
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 string GroupBy {
get {
return _groupBy ?? String.Empty;
}
set {
if (_groupBy != value) {
_groupBy = value;
OnDataSourceViewChanged(EventArgs.Empty);
}
}
}
public ParameterCollection GroupByParameters {
get {
if (_groupByParameters == null) {
_groupByParameters = new ParameterCollection();
_groupByParameters.ParametersChanged += new EventHandler(SelectParametersChangedEventHandler);
if (_tracking) {
((IStateManager)_groupByParameters).TrackViewState();
}
}
return _groupByParameters;
}
}
public ParameterCollection InsertParameters {
get {
if (_insertParameters == null) {
_insertParameters = new ParameterCollection();
}
return _insertParameters;
}
}
protected bool IsTrackingViewState {
get {
return _tracking;
}
}
public string OrderBy {
get {
return _orderBy ?? String.Empty;
}
set {
if (_orderBy != value) {
_orderBy = value;
OnDataSourceViewChanged(EventArgs.Empty);
}
}
}
public ParameterCollection OrderByParameters {
get {
if (_orderByParameters == null) {
_orderByParameters = new ParameterCollection();
_orderByParameters.ParametersChanged += new EventHandler(SelectParametersChangedEventHandler);
if (_tracking) {
((IStateManager)_orderByParameters).TrackViewState();
}
}
return _orderByParameters;
}
}
public string OrderGroupsBy {
get {
return _orderGroupsBy ?? String.Empty;
}
set {
if (_orderGroupsBy != value) {
_orderGroupsBy = value;
OnDataSourceViewChanged(EventArgs.Empty);
}
}
}
public ParameterCollection OrderGroupsByParameters {
get {
if (_orderGroupsByParameters == null) {
_orderGroupsByParameters = new ParameterCollection();
_orderGroupsByParameters.ParametersChanged += new EventHandler(SelectParametersChangedEventHandler);
if (_tracking) {
((IStateManager)_orderGroupsByParameters).TrackViewState();
}
}
return _orderGroupsByParameters;
}
}
[SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix",
Justification = "Removing 'New' would conflict with the Select() method.")]
public string SelectNew {
get {
return _selectNew ?? String.Empty;
}
set {
if (_selectNew != value) {
_selectNew = value;
OnDataSourceViewChanged(EventArgs.Empty);
}
}
}
public ParameterCollection SelectNewParameters {
get {
if (_selectNewParameters == null) {
_selectNewParameters = new ParameterCollection();
_selectNewParameters.ParametersChanged += new EventHandler(SelectParametersChangedEventHandler);
if (_tracking) {
((IStateManager)_selectNewParameters).TrackViewState();
}
}
return _selectNewParameters;
}
}
public bool StoreOriginalValuesInViewState {
get {
return _storeOriginalValuesInViewState;
}
set {
if (_storeOriginalValuesInViewState != value) {
_storeOriginalValuesInViewState = value;
OnDataSourceViewChanged(EventArgs.Empty);
}
}
}
public string TableName {
get {
return _tableName ?? String.Empty;
}
set {
if (_tableName != value) {
if (_reuseSelectContext) {
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
AtlasWeb.LinqDataSourceView_TableNameChanged, _owner.ID));
}
_tableName = value;
OnDataSourceViewChanged(EventArgs.Empty);
}
}
}
public ParameterCollection UpdateParameters {
get {
if (_updateParameters == null) {
_updateParameters = new ParameterCollection();
}
return _updateParameters;
}
}
public string Where {
get {
return _where ?? String.Empty;
}
set {
if (_where != value) {
_where = value;
OnDataSourceViewChanged(EventArgs.Empty);
}
}
}
public ParameterCollection WhereParameters {
get {
if (_whereParameters == null) {
_whereParameters = new ParameterCollection();
_whereParameters.ParametersChanged += new EventHandler(SelectParametersChangedEventHandler);
if (_tracking) {
((IStateManager)_whereParameters).TrackViewState();
}
}
return _whereParameters;
}
}
public event EventHandler ContextCreated {
add {
Events.AddHandler(EventContextCreated, value);
}
remove {
Events.RemoveHandler(EventContextCreated, value);
}
}
public event EventHandler ContextCreating {
add {
Events.AddHandler(EventContextCreating, value);
}
remove {
Events.RemoveHandler(EventContextCreating, value);
}
}
public event EventHandler ContextDisposing {
add {
Events.AddHandler(EventContextDisposing, value);
}
remove {
Events.RemoveHandler(EventContextDisposing, value);
}
}
public event EventHandler Deleted {
add {
Events.AddHandler(EventDeleted, value);
}
remove {
Events.RemoveHandler(EventDeleted, value);
}
}
public event EventHandler Deleting {
add {
Events.AddHandler(EventDeleting, value);
}
remove {
Events.RemoveHandler(EventDeleting, value);
}
}
internal event EventHandler Exception {
add {
Events.AddHandler(EventException, value);
}
remove {
Events.RemoveHandler(EventException, value);
}
}
public event EventHandler Inserted {
add {
Events.AddHandler(EventInserted, value);
}
remove {
Events.RemoveHandler(EventInserted, value);
}
}
public event EventHandler Inserting {
add {
Events.AddHandler(EventInserting, value);
}
remove {
Events.RemoveHandler(EventInserting, value);
}
}
public event EventHandler Selected {
add {
Events.AddHandler(EventSelected, value);
}
remove {
Events.RemoveHandler(EventSelected, value);
}
}
public event EventHandler Selecting {
add {
Events.AddHandler(EventSelecting, value);
}
remove {
Events.RemoveHandler(EventSelecting, value);
}
}
public event EventHandler Updated {
add {
Events.AddHandler(EventUpdated, value);
}
remove {
Events.RemoveHandler(EventUpdated, value);
}
}
public event EventHandler Updating {
add {
Events.AddHandler(EventUpdating, value);
}
remove {
Events.RemoveHandler(EventUpdating, value);
}
}
private static IQueryable AsQueryable(object o) {
IQueryable oQueryable = o as IQueryable;
if (oQueryable != null) {
return oQueryable;
}
// Wrap strings in IEnumerable instead of treating as IEnumerable.
string oString = o as string;
if (oString != null) {
return Queryable.AsQueryable(new string[] { oString });
}
IEnumerable oEnumerable = o as IEnumerable;
if (oEnumerable != null) {
// IEnumerable can be directly converted to an IQueryable.
Type genericType = LinqDataSourceHelper.FindGenericEnumerableType(o.GetType());
if (genericType != null) {
// The non-generic Queryable.AsQueryable gets called for array types, executing
// the FindGenericType logic again. Might want to investigate way to avoid this.
return Queryable.AsQueryable(oEnumerable);
}
// Wrap non-generic IEnumerables in IEnumerable