e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
838 lines
34 KiB
C#
838 lines
34 KiB
C#
namespace System.Web.UI.WebControls {
|
|
using System.Web.UI.WebControls.Expressions;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Specialized;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Security.Permissions;
|
|
using System.Web;
|
|
using System.Web.Resources;
|
|
using System.Web.UI;
|
|
using System.Web.UI.WebControls;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.ComponentModel;
|
|
|
|
|
|
public abstract class QueryableDataSourceView : DataSourceView, IStateManager {
|
|
//basic query parameters for any Queryable source
|
|
private ParameterCollection _whereParameters;
|
|
private ParameterCollection _orderByParameters;
|
|
private ParameterCollection _orderGroupsByParameters;
|
|
private ParameterCollection _selectNewParameters;
|
|
private ParameterCollection _groupByParameters;
|
|
|
|
// CUD operations
|
|
private ParameterCollection _deleteParameters;
|
|
private ParameterCollection _updateParameters;
|
|
private ParameterCollection _insertParameters;
|
|
|
|
private HttpContext _context;
|
|
private DataSourceControl _owner;
|
|
private IDynamicQueryable _queryable;
|
|
|
|
private string _groupBy;
|
|
private string _orderBy;
|
|
private string _orderGroupsBy;
|
|
private string _selectNew;
|
|
private string _where;
|
|
|
|
private bool _autoGenerateOrderByClause;
|
|
private bool _autoGenerateWhereClause;
|
|
private bool _autoPage = true;
|
|
private bool _autoSort = true;
|
|
private bool _isTracking;
|
|
|
|
protected static readonly object EventSelected = new object();
|
|
protected static readonly object EventSelecting = new object();
|
|
private static readonly object EventQueryCreated = new object();
|
|
|
|
// using Hashtable for original values so that ObjectStateFormatter will serialize it properly in ViewState.
|
|
private Hashtable _originalValues;
|
|
|
|
|
|
protected QueryableDataSourceView(DataSourceControl owner, string viewName, HttpContext context)
|
|
: this(owner, viewName, context, new DynamicQueryableWrapper()) {
|
|
_context = context;
|
|
_owner = owner;
|
|
}
|
|
|
|
internal QueryableDataSourceView(DataSourceControl owner, string viewName, HttpContext context, IDynamicQueryable queryable)
|
|
: base(owner, viewName) {
|
|
_context = context;
|
|
_queryable = queryable;
|
|
_owner = owner;
|
|
}
|
|
|
|
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 virtual bool AutoPage {
|
|
get {
|
|
return _autoPage;
|
|
}
|
|
set {
|
|
if (_autoPage != value) {
|
|
_autoPage = value;
|
|
OnDataSourceViewChanged(EventArgs.Empty);
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual bool AutoSort {
|
|
get {
|
|
return _autoSort;
|
|
}
|
|
set {
|
|
if (_autoSort != value) {
|
|
_autoSort = value;
|
|
OnDataSourceViewChanged(EventArgs.Empty);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override bool CanDelete {
|
|
get {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public override bool CanInsert {
|
|
get {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// 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 false;
|
|
}
|
|
}
|
|
|
|
public virtual ParameterCollection DeleteParameters {
|
|
get {
|
|
if (_deleteParameters == null) {
|
|
_deleteParameters = new ParameterCollection();
|
|
}
|
|
return _deleteParameters;
|
|
}
|
|
}
|
|
|
|
protected abstract Type EntityType {
|
|
get;
|
|
}
|
|
|
|
public virtual ParameterCollection GroupByParameters {
|
|
get {
|
|
if (_groupByParameters == null) {
|
|
_groupByParameters = new ParameterCollection();
|
|
_groupByParameters.ParametersChanged += new EventHandler(OnQueryParametersChanged);
|
|
if (_isTracking) {
|
|
DataSourceHelper.TrackViewState(_groupByParameters);
|
|
}
|
|
}
|
|
return _groupByParameters;
|
|
}
|
|
}
|
|
|
|
protected bool IsTrackingViewState {
|
|
get {
|
|
return _isTracking;
|
|
}
|
|
}
|
|
|
|
public virtual ParameterCollection InsertParameters {
|
|
get {
|
|
if (_insertParameters == null) {
|
|
_insertParameters = new ParameterCollection();
|
|
}
|
|
return _insertParameters;
|
|
}
|
|
}
|
|
|
|
public virtual ParameterCollection OrderByParameters {
|
|
get {
|
|
if (_orderByParameters == null) {
|
|
_orderByParameters = new ParameterCollection();
|
|
_orderByParameters.ParametersChanged += new EventHandler(OnQueryParametersChanged);
|
|
if (_isTracking) {
|
|
DataSourceHelper.TrackViewState(_orderByParameters);
|
|
}
|
|
}
|
|
return _orderByParameters;
|
|
}
|
|
}
|
|
|
|
public virtual ParameterCollection OrderGroupsByParameters {
|
|
get {
|
|
if (_orderGroupsByParameters == null) {
|
|
_orderGroupsByParameters = new ParameterCollection();
|
|
_orderGroupsByParameters.ParametersChanged += new EventHandler(OnQueryParametersChanged);
|
|
if (_isTracking) {
|
|
DataSourceHelper.TrackViewState(_orderGroupsByParameters);
|
|
}
|
|
}
|
|
return _orderGroupsByParameters;
|
|
}
|
|
}
|
|
|
|
|
|
public virtual string OrderBy {
|
|
get {
|
|
return _orderBy ?? String.Empty;
|
|
}
|
|
set {
|
|
if (_orderBy != value) {
|
|
_orderBy = value;
|
|
OnDataSourceViewChanged(EventArgs.Empty);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public virtual string OrderGroupsBy {
|
|
get {
|
|
return _orderGroupsBy ?? String.Empty;
|
|
}
|
|
set {
|
|
if (_orderGroupsBy != value) {
|
|
_orderGroupsBy = value;
|
|
OnDataSourceViewChanged(EventArgs.Empty);
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual string GroupBy {
|
|
get {
|
|
return _groupBy ?? String.Empty;
|
|
}
|
|
set {
|
|
if (_groupBy != value) {
|
|
_groupBy = value;
|
|
OnDataSourceViewChanged(EventArgs.Empty);
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual ParameterCollection SelectNewParameters {
|
|
get {
|
|
if (_selectNewParameters == null) {
|
|
_selectNewParameters = new ParameterCollection();
|
|
_selectNewParameters.ParametersChanged += new EventHandler(OnQueryParametersChanged);
|
|
if (_isTracking) {
|
|
DataSourceHelper.TrackViewState(_selectNewParameters);
|
|
}
|
|
}
|
|
return _selectNewParameters;
|
|
}
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix",
|
|
Justification = "SelectNew refers to a projection and 'New' is not used as a suffix in this case")]
|
|
public virtual string SelectNew {
|
|
get {
|
|
return _selectNew ?? String.Empty;
|
|
}
|
|
set {
|
|
if (_selectNew != value) {
|
|
_selectNew = value;
|
|
OnDataSourceViewChanged(EventArgs.Empty);
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual ParameterCollection WhereParameters {
|
|
get {
|
|
if (_whereParameters == null) {
|
|
_whereParameters = new ParameterCollection();
|
|
_whereParameters.ParametersChanged += new EventHandler(OnQueryParametersChanged);
|
|
if (_isTracking) {
|
|
DataSourceHelper.TrackViewState(_whereParameters);
|
|
}
|
|
}
|
|
return _whereParameters;
|
|
}
|
|
}
|
|
|
|
public virtual string Where {
|
|
get {
|
|
return _where ?? String.Empty;
|
|
}
|
|
set {
|
|
if (_where != value) {
|
|
_where = value;
|
|
OnDataSourceViewChanged(EventArgs.Empty);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public virtual ParameterCollection UpdateParameters {
|
|
get {
|
|
if (_updateParameters == null) {
|
|
_updateParameters = new ParameterCollection();
|
|
}
|
|
return _updateParameters;
|
|
}
|
|
}
|
|
|
|
|
|
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", Justification = "Derived classes will use this to as the ParametersChanged EventHandler")]
|
|
protected void OnQueryParametersChanged(object sender, EventArgs e) {
|
|
RaiseViewChanged();
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate", Justification = "An event exists already and it it protected")]
|
|
public void RaiseViewChanged() {
|
|
OnDataSourceViewChanged(EventArgs.Empty);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the result to apply query
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
protected abstract object GetSource(QueryContext context);
|
|
|
|
protected QueryContext CreateQueryContext(DataSourceSelectArguments arguments) {
|
|
IDictionary<string, object> whereParameters = WhereParameters.ToDictionary(_context, _owner);
|
|
IOrderedDictionary orderByParameters = OrderByParameters.GetValues(_context, _owner).ToCaseInsensitiveDictionary();
|
|
IDictionary<string, object> orderGroupsByParameters = OrderGroupsByParameters.ToDictionary(_context, _owner);
|
|
IDictionary<string, object> selectNewParameters = SelectNewParameters.ToDictionary(_context, _owner);
|
|
IDictionary<string, object> groupByParameters = GroupByParameters.ToDictionary(_context, _owner);
|
|
|
|
return new QueryContext(
|
|
whereParameters,
|
|
orderGroupsByParameters,
|
|
orderByParameters,
|
|
groupByParameters,
|
|
selectNewParameters,
|
|
arguments);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a select expression based on parameters and properties
|
|
/// </summary>
|
|
protected virtual IQueryable BuildQuery(DataSourceSelectArguments arguments) {
|
|
if (arguments == null) {
|
|
throw new ArgumentNullException("arguments");
|
|
}
|
|
|
|
// Create the query context
|
|
QueryContext context = CreateQueryContext(arguments);
|
|
|
|
// Clear out old values before selecting new data
|
|
_originalValues = null;
|
|
|
|
// Get the source of the query(root IQueryable)
|
|
object result = GetSource(context);
|
|
|
|
if (result != null) {
|
|
IQueryable source = QueryableDataSourceHelper.AsQueryable(result);
|
|
// Apply additional filterting
|
|
return ExecuteQuery(source, context);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
protected virtual IQueryable ExecuteQuery(IQueryable source, QueryContext context) {
|
|
// Execute Query
|
|
source = ExecuteQueryExpressions(source, context);
|
|
|
|
// Execute Sorting
|
|
source = ExecuteSorting(source, context);
|
|
|
|
// Execute Paging
|
|
source = ExecutePaging(source, context);
|
|
|
|
return source;
|
|
}
|
|
|
|
protected IQueryable ExecuteQueryExpressions(IQueryable source, QueryContext context) {
|
|
if (source != null) {
|
|
QueryCreatedEventArgs queryArgs = new QueryCreatedEventArgs(source);
|
|
OnQueryCreated(queryArgs);
|
|
source = queryArgs.Query ?? source;
|
|
|
|
// Support the Dynamic Expression language used by LinqDataSource
|
|
if (AutoGenerateWhereClause) {
|
|
if (!String.IsNullOrEmpty(Where)) {
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_WhereAlreadySpecified, _owner.ID));
|
|
}
|
|
source = QueryableDataSourceHelper.CreateWhereExpression(context.WhereParameters, source, _queryable);
|
|
}
|
|
else if (!String.IsNullOrEmpty(Where)) {
|
|
source = _queryable.Where(source, Where, context.WhereParameters.ToEscapedParameterKeys(_owner));
|
|
}
|
|
|
|
if (AutoGenerateOrderByClause) {
|
|
if (!String.IsNullOrEmpty(OrderBy)) {
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_OrderByAlreadySpecified, _owner.ID));
|
|
}
|
|
source = QueryableDataSourceHelper.CreateOrderByExpression(context.OrderByParameters, source, _queryable);
|
|
}
|
|
else if (!String.IsNullOrEmpty(OrderBy)) {
|
|
source = _queryable.OrderBy(source, OrderBy, context.OrderByParameters.ToEscapedParameterKeys(_owner));
|
|
}
|
|
|
|
|
|
string groupBy = GroupBy;
|
|
if (String.IsNullOrEmpty(groupBy)) {
|
|
if (!String.IsNullOrEmpty(OrderGroupsBy)) {
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_OrderGroupsByRequiresGroupBy, _owner.ID));
|
|
}
|
|
}
|
|
else {
|
|
source = _queryable.GroupBy(source, groupBy, "it", context.GroupByParameters.ToEscapedParameterKeys(_owner));
|
|
if (!String.IsNullOrEmpty(OrderGroupsBy)) {
|
|
source = _queryable.OrderBy(source, OrderGroupsBy, context.OrderGroupsByParameters.ToEscapedParameterKeys(_owner));
|
|
}
|
|
}
|
|
|
|
if (!String.IsNullOrEmpty(SelectNew)) {
|
|
source = _queryable.Select(source, SelectNew, context.SelectParameters.ToEscapedParameterKeys(_owner));
|
|
}
|
|
|
|
return source;
|
|
}
|
|
|
|
return source;
|
|
}
|
|
|
|
protected IQueryable ExecuteSorting(IQueryable source, QueryContext context) {
|
|
string sortExpression = context.Arguments.SortExpression;
|
|
|
|
if (CanSort && AutoSort && !String.IsNullOrEmpty(sortExpression)) {
|
|
source = _queryable.OrderBy(source, sortExpression);
|
|
}
|
|
return source;
|
|
}
|
|
|
|
protected IQueryable ExecutePaging(IQueryable source, QueryContext context) {
|
|
if (CanPage && AutoPage) {
|
|
if (CanRetrieveTotalRowCount && context.Arguments.RetrieveTotalRowCount) {
|
|
context.Arguments.TotalRowCount = _queryable.Count(source);
|
|
}
|
|
|
|
if ((context.Arguments.MaximumRows > 0) && (context.Arguments.StartRowIndex >= 0)) {
|
|
source = _queryable.Skip(source, context.Arguments.StartRowIndex);
|
|
source = _queryable.Take(source, context.Arguments.MaximumRows);
|
|
}
|
|
}
|
|
else if (context.Arguments.RetrieveTotalRowCount && (context.Arguments.TotalRowCount == -1)) {
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_PagingNotHandled, _owner.ID));
|
|
}
|
|
return source;
|
|
}
|
|
|
|
protected virtual void LoadViewState(object savedState) {
|
|
if (savedState != null) {
|
|
object[] myState = (object[])savedState;
|
|
|
|
if (myState[0] != null) {
|
|
((IStateManager)WhereParameters).LoadViewState(myState[0]);
|
|
}
|
|
if (myState[1] != null) {
|
|
((IStateManager)OrderByParameters).LoadViewState(myState[1]);
|
|
}
|
|
if (myState[2] != null) {
|
|
((IStateManager)GroupByParameters).LoadViewState(myState[2]);
|
|
}
|
|
if (myState[3] != null) {
|
|
((IStateManager)OrderGroupsByParameters).LoadViewState(myState[3]);
|
|
}
|
|
if (myState[4] != null) {
|
|
((IStateManager)SelectNewParameters).LoadViewState(myState[4]);
|
|
}
|
|
if (myState[5] != null) {
|
|
_originalValues = (Hashtable)myState[5];
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual object SaveViewState() {
|
|
object[] myState = new object[6];
|
|
myState[0] = DataSourceHelper.SaveViewState(_whereParameters);
|
|
myState[1] = DataSourceHelper.SaveViewState(_orderByParameters);
|
|
myState[2] = DataSourceHelper.SaveViewState(_groupByParameters);
|
|
myState[3] = DataSourceHelper.SaveViewState(_orderGroupsByParameters);
|
|
myState[4] = DataSourceHelper.SaveViewState(_selectNewParameters);
|
|
if ((_originalValues != null) && (_originalValues.Count > 0)) {
|
|
myState[5] = _originalValues;
|
|
}
|
|
|
|
return myState;
|
|
}
|
|
|
|
|
|
protected virtual void TrackViewState() {
|
|
_isTracking = true;
|
|
DataSourceHelper.TrackViewState(_whereParameters);
|
|
DataSourceHelper.TrackViewState(_orderByParameters);
|
|
DataSourceHelper.TrackViewState(_groupByParameters);
|
|
DataSourceHelper.TrackViewState(_orderGroupsByParameters);
|
|
DataSourceHelper.TrackViewState(_selectNewParameters);
|
|
}
|
|
|
|
protected internal override IEnumerable ExecuteSelect(DataSourceSelectArguments arguments) {
|
|
ClearOriginalValues();
|
|
|
|
IQueryable source = BuildQuery(arguments);
|
|
|
|
IList results = source.ToList(source.ElementType);
|
|
|
|
// Store original values for concurrency
|
|
StoreOriginalValues(results);
|
|
|
|
return results;
|
|
}
|
|
|
|
protected void ClearOriginalValues() {
|
|
_originalValues = null;
|
|
}
|
|
|
|
protected virtual IDictionary GetOriginalValues(IDictionary keys) {
|
|
// Table data is stored in a hashtable with column names for keys and an ArrayList of row data for values.
|
|
// i.e, Hashtable { ID = ArrayList { 0, 1, 2 }, Name = ArrayList { "A", "B", "C" } }
|
|
if (_originalValues != null) {
|
|
// matches list keeps track of row indexes which match.
|
|
List<bool> matches = new List<bool>();
|
|
foreach (DictionaryEntry entry in keys) {
|
|
string propertyName = (String)entry.Key;
|
|
if (_originalValues.ContainsKey(propertyName)) {
|
|
object propertyValue = entry.Value;
|
|
// get the row values for the current column.
|
|
ArrayList values = (ArrayList)_originalValues[propertyName];
|
|
for (int i = 0; i < values.Count; i++) {
|
|
if (matches.Count <= i) { // first column
|
|
matches.Add(OriginalValueMatches(values[i], propertyValue));
|
|
}
|
|
else if (matches[i] == true) { // subsequent columns
|
|
matches[i] = OriginalValueMatches(values[i], propertyValue);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int rowIndex = matches.IndexOf(true);
|
|
// no rows match or too many rows match.
|
|
if ((rowIndex < 0) || (matches.IndexOf(true, rowIndex + 1) >= 0)) {
|
|
throw new InvalidOperationException(AtlasWeb.LinqDataSourceView_OriginalValuesNotFound);
|
|
}
|
|
// get original values for the matching row.
|
|
Dictionary<string, object> rowValues = new Dictionary<string, object>(_originalValues.Count,
|
|
StringComparer.OrdinalIgnoreCase);
|
|
foreach (DictionaryEntry entry in _originalValues) {
|
|
ArrayList value = (ArrayList)entry.Value;
|
|
rowValues.Add((string)entry.Key, value[rowIndex]);
|
|
}
|
|
return rowValues;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
protected virtual void StoreOriginalValues(IList results) {
|
|
// Derived classes can override this function and call the overload
|
|
// to determine which columns it should store for optimistic concurrency
|
|
}
|
|
|
|
protected void StoreOriginalValues(IList results, Func<PropertyDescriptor, bool> include) {
|
|
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(EntityType);
|
|
int numRows = results.Count;
|
|
int maxColumns = props.Count;
|
|
_originalValues = new Hashtable(maxColumns, StringComparer.OrdinalIgnoreCase);
|
|
foreach (PropertyDescriptor p in props) {
|
|
if (include(p) && p.PropertyType.IsSerializable) {
|
|
ArrayList values = new ArrayList(numRows);
|
|
_originalValues[p.Name] = values;
|
|
foreach (object currentRow in results) {
|
|
values.Add(p.GetValue(currentRow));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public int Update(IDictionary keys, IDictionary values, IDictionary oldValues) {
|
|
return ExecuteUpdate(keys, values, oldValues);
|
|
}
|
|
|
|
public int Delete(IDictionary keys, IDictionary oldValues) {
|
|
return ExecuteDelete(keys, oldValues);
|
|
}
|
|
|
|
public int Insert(IDictionary values) {
|
|
return ExecuteInsert(values);
|
|
}
|
|
|
|
protected QueryableDataSourceEditData BuildDeleteObject(IDictionary keys, IDictionary oldValues, IDictionary<string, Exception> validationErrors) {
|
|
QueryableDataSourceEditData editData = new QueryableDataSourceEditData();
|
|
Type dataObjectType = EntityType;
|
|
IDictionary caseInsensitiveOldValues = new OrderedDictionary(StringComparer.OrdinalIgnoreCase);
|
|
IDictionary originalValues = GetOriginalValues(keys);
|
|
|
|
ParameterCollection deleteParameters = DeleteParameters;
|
|
if (!DataSourceHelper.MergeDictionaries(dataObjectType,
|
|
deleteParameters,
|
|
keys,
|
|
caseInsensitiveOldValues,
|
|
validationErrors)) {
|
|
return editData;
|
|
}
|
|
|
|
if (!DataSourceHelper.MergeDictionaries(dataObjectType,
|
|
deleteParameters,
|
|
oldValues,
|
|
caseInsensitiveOldValues,
|
|
validationErrors)) {
|
|
return editData;
|
|
|
|
}
|
|
|
|
if (originalValues != null) {
|
|
if (!DataSourceHelper.MergeDictionaries(dataObjectType,
|
|
deleteParameters,
|
|
originalValues,
|
|
caseInsensitiveOldValues,
|
|
validationErrors)) {
|
|
return editData;
|
|
}
|
|
}
|
|
|
|
editData.OriginalDataObject = DataSourceHelper.BuildDataObject(dataObjectType, caseInsensitiveOldValues, validationErrors);
|
|
return editData;
|
|
}
|
|
|
|
protected QueryableDataSourceEditData BuildInsertObject(IDictionary values, IDictionary<string, Exception> validationErrors) {
|
|
QueryableDataSourceEditData editData = new QueryableDataSourceEditData();
|
|
Type dataObjectType = EntityType;
|
|
IDictionary caseInsensitiveNewValues = new OrderedDictionary(StringComparer.OrdinalIgnoreCase);
|
|
|
|
if (!DataSourceHelper.MergeDictionaries(dataObjectType,
|
|
InsertParameters,
|
|
InsertParameters.GetValues(_context, _owner),
|
|
caseInsensitiveNewValues,
|
|
validationErrors)) {
|
|
return editData;
|
|
}
|
|
|
|
if (!DataSourceHelper.MergeDictionaries(dataObjectType,
|
|
InsertParameters,
|
|
values,
|
|
caseInsensitiveNewValues, validationErrors)) {
|
|
return editData;
|
|
}
|
|
|
|
editData.NewDataObject = DataSourceHelper.BuildDataObject(dataObjectType, caseInsensitiveNewValues, validationErrors);
|
|
return editData;
|
|
}
|
|
|
|
protected QueryableDataSourceEditData BuildUpdateObjects(IDictionary keys, IDictionary values, IDictionary oldValues, IDictionary<string, Exception> validationErrors) {
|
|
QueryableDataSourceEditData editData = new QueryableDataSourceEditData();
|
|
Type dataObjectType = EntityType;
|
|
IDictionary caseInsensitiveNewValues = new OrderedDictionary(StringComparer.OrdinalIgnoreCase);
|
|
IDictionary caseInsensitiveOldValues = new OrderedDictionary(StringComparer.OrdinalIgnoreCase);
|
|
IDictionary originalValues = GetOriginalValues(keys);
|
|
|
|
// We start out with the old values, just to pre-populate the list with items
|
|
// that might not have corresponding new values. For example if a GridView has
|
|
// a read-only field, there will be an old value, but no new value. The data object
|
|
// still has to have *some* value for a given field, so we just use the old value.
|
|
ParameterCollection updateParameters = UpdateParameters;
|
|
|
|
// If we have validation errors bail out while merging bailout
|
|
|
|
if (!DataSourceHelper.MergeDictionaries(dataObjectType,
|
|
updateParameters,
|
|
oldValues,
|
|
caseInsensitiveOldValues,
|
|
caseInsensitiveNewValues,
|
|
validationErrors)) {
|
|
return editData;
|
|
}
|
|
|
|
if (!DataSourceHelper.MergeDictionaries(dataObjectType,
|
|
updateParameters,
|
|
keys,
|
|
caseInsensitiveOldValues,
|
|
caseInsensitiveNewValues,
|
|
validationErrors)) {
|
|
return editData;
|
|
}
|
|
|
|
if (originalValues != null) {
|
|
if (!DataSourceHelper.MergeDictionaries(dataObjectType,
|
|
updateParameters,
|
|
originalValues,
|
|
caseInsensitiveOldValues,
|
|
caseInsensitiveNewValues,
|
|
validationErrors)) {
|
|
return editData;
|
|
}
|
|
}
|
|
|
|
if (!DataSourceHelper.MergeDictionaries(dataObjectType,
|
|
updateParameters,
|
|
values,
|
|
caseInsensitiveNewValues,
|
|
validationErrors)) {
|
|
return editData;
|
|
}
|
|
|
|
editData.NewDataObject = DataSourceHelper.BuildDataObject(dataObjectType, caseInsensitiveNewValues, validationErrors);
|
|
|
|
if (editData.NewDataObject != null) {
|
|
editData.OriginalDataObject = DataSourceHelper.BuildDataObject(dataObjectType, caseInsensitiveOldValues, validationErrors);
|
|
}
|
|
return editData;
|
|
}
|
|
|
|
protected virtual int DeleteObject(object oldEntity) {
|
|
return 0;
|
|
}
|
|
|
|
protected virtual int UpdateObject(object oldEntity, object newEntity) {
|
|
return 0;
|
|
}
|
|
|
|
protected virtual int InsertObject(object newEntity) {
|
|
return 0;
|
|
}
|
|
|
|
protected abstract void HandleValidationErrors(IDictionary<string, Exception> errors, DataSourceOperation operation);
|
|
|
|
protected override int ExecuteDelete(IDictionary keys, IDictionary oldValues) {
|
|
IDictionary<string, Exception> errors = new Dictionary<string, Exception>(StringComparer.OrdinalIgnoreCase);
|
|
QueryableDataSourceEditData editData = BuildDeleteObject(keys, oldValues, errors);
|
|
|
|
if (errors.Any()) {
|
|
HandleValidationErrors(errors, DataSourceOperation.Delete);
|
|
}
|
|
else {
|
|
return DeleteObject(editData.OriginalDataObject);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
protected override int ExecuteInsert(IDictionary values) {
|
|
IDictionary<string, Exception> errors = new Dictionary<string, Exception>(StringComparer.OrdinalIgnoreCase);
|
|
QueryableDataSourceEditData editData = BuildInsertObject(values, errors);
|
|
if (errors.Any()) {
|
|
HandleValidationErrors(errors, DataSourceOperation.Insert);
|
|
}
|
|
else {
|
|
return InsertObject(editData.NewDataObject);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
protected override int ExecuteUpdate(IDictionary keys, IDictionary values, IDictionary oldValues) {
|
|
IDictionary<string, Exception> errors = new Dictionary<string, Exception>(StringComparer.OrdinalIgnoreCase);
|
|
QueryableDataSourceEditData editData = BuildUpdateObjects(keys, values, oldValues, errors);
|
|
if (errors.Any()) {
|
|
HandleValidationErrors(errors, DataSourceOperation.Update);
|
|
}
|
|
else {
|
|
return UpdateObject(editData.OriginalDataObject, editData.NewDataObject);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
public event EventHandler<QueryCreatedEventArgs> QueryCreated {
|
|
add {
|
|
Events.AddHandler(EventQueryCreated, value);
|
|
}
|
|
remove {
|
|
Events.RemoveHandler(EventQueryCreated, value);
|
|
}
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#")]
|
|
protected virtual void OnQueryCreated(QueryCreatedEventArgs e) {
|
|
EventHandler<QueryCreatedEventArgs> handler = (EventHandler<QueryCreatedEventArgs>)Events[EventQueryCreated];
|
|
if (handler != null) {
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
private bool OriginalValueMatches(object originalValue, object value) {
|
|
// NOTE: Comparing IEnumerable contents instead of instances to ensure that
|
|
// timestamp columns (of type byte[]) can be matched appropriately.
|
|
IEnumerable originalValueEnumerable = originalValue as IEnumerable;
|
|
IEnumerable valueEnumerable = value as IEnumerable;
|
|
if ((originalValueEnumerable != null) && (valueEnumerable != null)) {
|
|
return QueryableDataSourceHelper.EnumerableContentEquals(originalValueEnumerable, valueEnumerable);
|
|
}
|
|
return originalValue.Equals(value);
|
|
}
|
|
|
|
#region IStateManager Members
|
|
|
|
bool IStateManager.IsTrackingViewState {
|
|
get { return IsTrackingViewState; }
|
|
}
|
|
|
|
void IStateManager.LoadViewState(object state) {
|
|
LoadViewState(state);
|
|
}
|
|
|
|
object IStateManager.SaveViewState() {
|
|
return SaveViewState();
|
|
}
|
|
|
|
void IStateManager.TrackViewState() {
|
|
TrackViewState();
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|