Click here to Skip to main content
15,886,799 members
Articles / Web Development / ASP.NET

Using Silverlight in Enterprise: RAD of User Friendly Database Access

Rate me:
Please Sign up or sign in to vote.
4.81/5 (19 votes)
31 Jul 2009CPOL8 min read 58.1K   7K   81  
This article introduces FulcrumWeb RAD Framework - A Silverlight UI Engine to build user friendly database driven applications
/********************************************************************
 *  FulcrumWeb RAD Framework - Fulcrum of your business             *
 *  Copyright (c) 2002-2009 FulcrumWeb, ALL RIGHTS RESERVED         *
 *                                                                  *
 *  THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      *
 *  FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        *
 *  COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       *
 *  AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  *
 *  AND PERMISSION FROM FULCRUMWEB. CONSULT THE END USER LICENSE    *
 *  AGREEMENT FOR INFORMATION ON ADDITIONAL RESTRICTIONS.           *
 ********************************************************************/

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Framework.Silverlight.Client.AppServer;

namespace Framework.Silverlight.Client
{
  /// <summary>
  /// Represents base features for Entity 
  /// </summary>
  public class _CxBaseEntity : IxDataObject, IxValueProvider
  {
    /// <summary>
    /// Occurs when Attribute with depended attributes had changed.
    /// </summary>
    public event DxDependencyAttributeChanged DependencyAttributeChanged;

    //----------------------------------------------------------------------------
    /// <summary>
    /// Occurs when data had change.
    /// </summary>
    public event EventHandler DataChanged;

    //----------------------------------------------------------------------------
    /// <summary>
    /// Occurs when changes of data was commited.
    /// </summary>
    public event EventHandler DataCommited;

    //----------------------------------------------------------------------------
    /// <summary>
    /// Occurs when changes of data was reverted.
    /// </summary>
    public event EventHandler DataReverted;
    //----------------------------------------------------------------------------

    private readonly Dictionary<string, CxAttributeValue> m_Attributes = new Dictionary<string, CxAttributeValue>();
    private bool m_IsDisposed;
    private readonly Dictionary<string, CxAttributeValue> m_PrimaryKeys = new Dictionary<string, CxAttributeValue>();
    private CxEntityUsage m_EntityUsage;
    private int m_ChangesCounter;

    //----------------------------------------------------------------------------
    /// <summary>
    /// Validates all atrributes values. 
    /// </summary>
    protected virtual void Validate()
    {
      foreach (CxAttributeValue attribute in m_Attributes.Values)
      {
        attribute.Validate();
      }
    }
    //----------------------------------------------------------------------------
    /// <summary>
    /// Sets the value to dynamically generated property.
    /// </summary>
    /// <param name="attrValue">The property value.</param>
    public virtual void SetDynamicProperty(CxAttributeValue attrValue)
    {
      PropertyInfo pInfo = GetType().GetProperty(attrValue.DynamicPropertyName);
      if (pInfo == null)
      {
        throw new ExApplicationException("Dynamic property with name '{0}' does " +
            "not exists in dynamic class '{1}'.", attrValue.DynamicPropertyName, GetType().Name);
      }
      pInfo.SetValue(this, attrValue, null);

      m_Attributes.Add(attrValue.AttributeId, attrValue);

      if (attrValue.IsPrimaryKey)
      {
        m_PrimaryKeys.Add(attrValue.AttributeId.ToUpper(), attrValue);
      }

      attrValue.DataChanged += Value_DataChanged;
      attrValue.DataCommited += Value_DataCommited;
      attrValue.DataReverted += Value_DataReverted;
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Sets rowsource.
    /// </summary>
    /// <param name="unfilteredRowSources">Dictionary of unfiltered rowsources.</param>
    /// <param name="filteredRowSources">List of unfiltered rowsources.</param>
    public void SetRowSources(
      IDictionary<string, CxClientRowSource> unfilteredRowSources,
      IList<CxClientRowSource> filteredRowSources)
    {
      foreach (CxAttributeValue attrValue in m_Attributes.Values)
      {
        if (unfilteredRowSources.ContainsKey(attrValue.AttributeMetadata.RowSourceId) &&
          !attrValue.AttributeMetadata.HasRowSourceFilter)
        {
          attrValue.RowSource = unfilteredRowSources[attrValue.AttributeMetadata.RowSourceId];
        }
      }


      foreach (CxClientRowSource rowSource in filteredRowSources)
      {
        if (m_Attributes.ContainsKey(rowSource.OwnerAttributeId))
        {
          m_Attributes[rowSource.OwnerAttributeId].RowSource = rowSource;

        }
      }
    }
    //----------------------------------------------------------------------------
    /// <summary>
    /// Handles the CxAttributeValue.DataReverted event.
    /// </summary>
    void Value_DataReverted(object sender, EventArgs e)
    {
      m_ChangesCounter--;
      if (m_ChangesCounter == 0)
      {
        OnDataReverted();
      }
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Handles the CxAttributeValue.DataCommited event.
    /// </summary>
    void Value_DataCommited(object sender, EventArgs e)
    {
      m_ChangesCounter--;
      if (m_ChangesCounter == 0)
      {
        OnDataCommited();
      }
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Handles the CxAttributeValue.DataChanged event.
    /// </summary>
    void Value_DataChanged(object sender, EventArgs e)
    {
      m_ChangesCounter++;
      OnDataChanged();
      CxAttributeValue attributeValue = (CxAttributeValue)sender;
      if (attributeValue.HasDependencies)
      {
        OnDependencyAttributeChanged(new CxDependencyAttributeChangedEventArgs(attributeValue.AttributeId));
      }
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Raises the DependencyAttributeChanged event.
    /// </summary>
    protected virtual void OnDependencyAttributeChanged(CxDependencyAttributeChangedEventArgs e)
    {
      if (DependencyAttributeChanged != null)
      {
        DependencyAttributeChanged(this, e);
      }
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Raises the DataChanged event.
    /// </summary>
    protected virtual void OnDataChanged()
    {
      if (DataChanged != null)
      {
        DataChanged(this, EventArgs.Empty);
      }
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Raises the DataReverted event.
    /// </summary>
    protected virtual void OnDataReverted()
    {
      if (DataReverted != null)
      {
        DataReverted(this, EventArgs.Empty);
      }
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Raises the DataCommited event.
    /// </summary>
    protected virtual void OnDataCommited()
    {
      if (DataCommited != null)
      {
        DataCommited(this, EventArgs.Empty);
      }
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Commits all the changes made to this DataObject since
    /// the last time AcceptChanges() was called.
    /// <param name="validate">True - validate befor accepting.</param>
    /// </summary>
    public void AcceptChanges(bool validate)
    {
      foreach (IxDataObject attribute in m_Attributes.Values)
      {
        attribute.AcceptChanges(validate);
      }
      m_ChangesCounter = 0;
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Commits all changes made to this DataObject since
    /// the last time AcceptChanges() was called.
    /// </summary>
    public void AcceptChanges()
    {
      AcceptChanges(true);
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Rolls back all changes that have been made to the
    /// DataObject since the last time AcceptChanges() was called.
    /// </summary>
    public void RejectChanges()
    {
      foreach (IxDataObject attribute in m_Attributes.Values)
      {
        attribute.RejectChanges();
      }
      m_WaitingToUpload.Clear();
      m_ChangesCounter = 0;
    }

    //----------------------------------------------------------------------------
    /// <summary>
    ///  Performs application-defined tasks associated with freeing, releasing,
    ///  or resetting unmanaged resources.
    /// </summary>
    public void Dispose()
    {
      if (!m_IsDisposed)
      {
        foreach (IxDataObject attribute in m_Attributes.Values)
        {
          attribute.DataChanged -= Value_DataChanged;
          attribute.DataCommited -= Value_DataCommited;
          attribute.DataReverted -= Value_DataReverted;
        }
        foreach (KeyValuePair<string, CxFileToUpload> pair in m_WaitingToUpload)
        {
          pair.Value.Stream.Close();
        }
        m_IsDisposed = true;

      }
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Gets the value from dynamically generated property.
    /// </summary>
    /// <param name="attributeName">Entity Atrtribute name.</param>
    /// <returns></returns>
    private object GetDynamicPropertyValue(string attributeName)
    {
      return GetDynamicProperty(attributeName).Value;
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Gets dynamically generated property.
    /// </summary>
    /// <param name="attributeId">Entity Atrtribute Id.</param>
    /// <returns>Instance of CxAttributeValue</returns>
    public CxAttributeValue GetDynamicProperty(string attributeId)
    {
      string upperName = attributeId.ToUpper();
      if (!m_Attributes.ContainsKey(upperName))
      {
        throw new ExApplicationException("Property that associated with attribute '{0}' does " +
            "not exists in dynamic class '{1}'.", attributeId, GetType().Name);
      }
      return m_Attributes[upperName];
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Indexed property to get value by name.
    /// </summary>
    public object this[string name]
    {
      get { return GetDynamicPropertyValue(name); }
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Compares primary key(s) values with specified.
    /// </summary>
    /// <param name="pkList">List of values to compare.</param>
    /// <returns>Returns true if primary key(s) is identical or false if otherwise. </returns>
    public virtual bool ComparePk(IList<CxAttributeSnapShot> pkList)
    {
      if (m_PrimaryKeys.Count != pkList.Count)//Primary keys count is different
      {
        return false;
      }

      foreach (CxAttributeSnapShot pkSnapShot in pkList)
      {
        if (!m_PrimaryKeys.ContainsKey(pkSnapShot.AttributeId))// Primary keys names is different
        {
          return false;
        }
      }

      foreach (CxAttributeSnapShot pkSnapShot in pkList)
      {
        if (!m_PrimaryKeys[pkSnapShot.AttributeId].Equals(pkSnapShot.AttributeValue))// Primary keys value is different
        {
          return false;
        }
      }

      return true;
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Compares primary key(s) values with specified.
    /// </summary>
    /// <param name="pkList">List of values to compare.</param>
    /// <returns>Returns true if primary key(s) is identical or false if otherwise. </returns>
    public virtual bool ComparePk(IDictionary<string, object> pkList)
    {
      if (m_PrimaryKeys.Count != pkList.Count)//Primary keys count is different
      {
        return false;
      }

      foreach (KeyValuePair<string, object> pk in pkList)
      {
        if (!m_PrimaryKeys.ContainsKey(pk.Key))
          // Primary keys are different fields
          return false;

        // Initialize the primary key value.
        CxAttributeValue entityPkValue = m_PrimaryKeys[pk.Key];

        if (entityPkValue.Value == null && pk.Value == null)
          continue;

        if (entityPkValue.Value == null || pk.Value == null)
          return false;
        if (!entityPkValue.Value.Equals(pk.Value))
          return false;
      }


      return true;
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Gets CxEntityUsage that associates with this Entity.
    /// </summary>
    public CxEntityUsage EntityUsage
    {
      get { return m_EntityUsage; }
      internal set { m_EntityUsage = value; }
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Returns command with the given name.
    /// </summary>
    /// <param name="commandId">command Id</param>
    /// <returns>command with the given name</returns>
    public CxCommand GetCommand(string commandId)
    {
      IList<CxClientCommandMetadata> result = (from commandMetadata in EntityUsage.EntityMetadata.Commands
                                               where commandMetadata.Id == commandId
                                               select commandMetadata).ToArray();

      if (result.Count == 0)
      {
        throw new ExApplicationException("Command with Id '{0}' is not defined in" +
            "EntityUsage with Id '{1}'.", commandId, EntityUsage.EntityMetadata.Id);
      }

      CxCommand cmd = new CxCommand(result[0]);
      return cmd;

    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Gets dictionary of primary keys.
    ///     key - key name;   value - key value;
    /// </summary>
    public IDictionary<string, CxAttributeValue> PrimaryKeys
    {
      get { return m_PrimaryKeys; }
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Gets value that defines, has this entity uncommitted changes or not.
    /// </summary>
    public bool HasChanges
    {
      get { return m_ChangesCounter > 0; }
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Gets or sets value that defines there was DataObject is commited.
    /// </summary>
    public bool IsCommited { get; set; }
    //----------------------------------------------------------------------------
    /// <summary>
    /// Refreshes entity by given CxExpressionResult.
    /// </summary>
    /// <param name="exprResult">CxExpressionResult with fresh values.</param>
    public void Refresh(CxExpressionResult exprResult)
    {
      foreach (KeyValuePair<CxClientAttributeMetadata, object> pair in exprResult.Entity)
      {
        m_Attributes[pair.Key.Id].Value = pair.Value;
      }
      foreach (CxClientRowSource rs in exprResult.FilteredRowSources)
      {
        m_Attributes[rs.OwnerAttributeId].RowSource = rs;
      }
      foreach (KeyValuePair<string, CxAttributeValue> pair in m_Attributes)
      {
        if (!string.IsNullOrEmpty(pair.Value.AttributeMetadata.RowSourceId) &&
          exprResult.UnfilteredRowSources.ContainsKey(pair.Value.AttributeMetadata.RowSourceId))
        {
          pair.Value.RowSource = exprResult.UnfilteredRowSources[pair.Value.AttributeMetadata.RowSourceId];
        }
      }
    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Dictionary of waiting to upload streams.
    /// key - attribute id; value - stream to upload;
    /// </summary>
    private readonly Dictionary<string, CxFileToUpload> m_WaitingToUpload = new Dictionary<string, CxFileToUpload>();
    //----------------------------------------------------------------------------
    /// <summary>
    /// Adds Stream to upload.
    /// </summary>
    /// <param name="stream">Stream to upload</param>
    /// <param name="attributeId">Attribute id, appropriated with given Stream.</param>
    /// <param name="fileName">File name.</param>
    public virtual void AddStreamToUpload(Stream stream, string attributeId, string fileName)
    {
      if (!m_WaitingToUpload.ContainsKey(attributeId))
      {
        m_WaitingToUpload.Add(attributeId, new CxFileToUpload { Stream = stream, FileName = fileName });
      }
      else
      {
        m_WaitingToUpload[attributeId].Stream.Close();
        m_WaitingToUpload[attributeId] = new CxFileToUpload { Stream = stream, FileName = fileName };
      }
      CxAttributeValue attrValue = m_Attributes[attributeId];
      CxClientAttributeMetadata attrMetadata = attrValue.AttributeMetadata;

      //set file name in appropriated attribute 
      if (!string.IsNullOrEmpty(attrMetadata.BlobFileNameAttributeId))
      {
        GetDynamicProperty(attrMetadata.BlobFileNameAttributeId).Value = fileName;
      }

      //set file size in appropriated attribute 
      if (!string.IsNullOrEmpty(attrMetadata.BlobFileSizeAttributeId))
      {
        GetDynamicProperty(attrMetadata.BlobFileSizeAttributeId).Value = stream.Length;
      }


    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Adds to removing BLOB from server.
    /// </summary>
    /// <param name="attributeId">Attribute id that contains BLOB.</param>
    public virtual void AddToDeleteBlob(string attributeId)
    {
      CxAttributeValue stateAttrValue = m_Attributes[CxEntityUsage.GetBlobStateAttributeId(attributeId)];
      stateAttrValue.Value = CxEntityUsage.REMOVE_BLOB_FROM_DB;

      CxAttributeValue attrValue = m_Attributes[attributeId];
      CxClientAttributeMetadata attrMetadata = attrValue.AttributeMetadata;
      //set file name in appropriated attribute 
      if (!string.IsNullOrEmpty(attrMetadata.BlobFileNameAttributeId))
      {
        GetDynamicProperty(attrMetadata.BlobFileNameAttributeId).Value = null;
      }

      //set file size in appropriated attribute 
      if (!string.IsNullOrEmpty(attrMetadata.BlobFileSizeAttributeId))
      {
        GetDynamicProperty(attrMetadata.BlobFileSizeAttributeId).Value = null;
      }


    }

    //----------------------------------------------------------------------------
    /// <summary>
    /// Returns dictionary of waiting to upload streams.
    /// </summary>
    /// <returns>Dictionary with streams.</returns>
    public virtual Dictionary<string, CxFileToUpload> GetStreamsToUpload()
    {
      return m_WaitingToUpload;
    }

  }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Ukraine Ukraine
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions