Beispiel #1
0
        /// <summary>
        /// Perform CRUD action for the item(s) in the params list.
        /// An <see cref="IEnumerable{T}"/> of *modified* items is returned; the modification is to update the primary key to the correct new value for inserted items.
        /// If the input item does not support field writes/inserts as needed then an <see cref="ExpandoObject"/> corresponding to the updated item is returned instead.
        /// </summary>
        /// <param name="action">The ORM action</param>
        /// <param name="connection">The connection to use</param>
        /// <param name="items">The item or items</param>
        /// <returns>The list of modified items</returns>
        /// <remarks>Here and in <see cref="UpsertItemPK"/> we always return the modified original object where possible</remarks>
        internal Tuple <int, IEnumerable <T> > ActionOnItemsWithOutput(OrmAction action, DbConnection connection, IEnumerable <object> items)
        {
            List <T> modifiedItems = null;

            if (action == OrmAction.Insert)
            {
                modifiedItems = new List <T>();
            }
            int count    = 0;
            int affected = 0;

            ValidateAction(items, action);
            foreach (var item in items)
            {
                if (Validator.ShouldPerformAction(item, action))
                {
                    object result;
                    affected += ActionOnItem(out result, action, item, connection);
                    if (action == OrmAction.Insert)
                    {
                        var modified = result ?? item;
                        if (IsGeneric && !(modified is T))
                        {
                            modified = New(modified, false);
                        }
                        modifiedItems.Add((T)modified);
                    }
                    Validator.HasPerformedAction(item, action);
                }
                count++;
            }
            return(new Tuple <int, IEnumerable <T> >(affected, modifiedItems));
        }
Beispiel #2
0
        /// <summary>
        /// Save, Insert, Update or Delete an item.
        /// Save means: update item if PK field or fields are present and at non-default values, insert otherwise.
        /// On inserting an item with a single PK and a sequence/identity the PK field of the item itself is
        /// a) created if not present and b) filled with the new PK value, where this is possible (examples of cases
        /// where not possible are: fields can't be created on POCOs, property values can't be set on immutable items
        /// such as anonymously typed objects).
        /// </summary>
        /// <param name="modified">The modified item with PK added, if <see cref="OrmAction.Insert"/></param>
        /// <param name="originalAction">Save, Insert, Update or Delete</param>
        /// <param name="item">item</param>
        /// <param name="connection">The connection to use</param>
        /// <returns>The number of items affected</returns>
        /// <remarks>
        /// It *is* technically possibly (by writing to private backing fields) to change the field value in anonymously
        /// typed objects - http://stackoverflow.com/a/30242237/795690 - and bizarrely VB supports writing to fields in
        /// anonymously typed objects natively even though C# doesn't - http://stackoverflow.com/a/9065678/795690 (which
        /// sounds as if it means that if this part of the library was written in VB then doing this would be officially
        /// supported? not quite sure, that assumes that the different implementations of anonymous types can co-exist)
        /// </remarks>
        private int ActionOnItem(out object modified, OrmAction originalAction, object item, DbConnection connection)
        {
            OrmAction revisedAction;
            DbCommand command = CreateActionCommand(originalAction, item, out revisedAction);

            command.Connection = connection;
            if (revisedAction == OrmAction.Insert && PrimaryKeyInfo.SequenceNameOrIdentityFunction != null)
            {
                // *All* DBs return a huge sized number for their identity by default, following Massive we are normalising to int
                var pk = Convert.ToInt32(Scalar(command));
                modified = UpsertItemPK(
                    item, pk,
                    // Don't create clone items on Save as these will then be discarded; but do still update the PK if clone not required
                    originalAction == OrmAction.Insert);
                return(1);
            }
            else
            {
                modified = null;
                return(Execute(command));
            }
        }
Beispiel #3
0
#pragma warning restore CS1998
        #endregion

        #region ORM actions
        /// <summary>
        /// Save, Insert, Update or Delete an item.
        /// Save means: update item if PK field or fields are present and at non-default values, insert otherwise.
        /// On inserting an item with a single PK and a sequence/identity the PK field of the item itself is
        /// a) created if not present and b) filled with the new PK value, where this is possible (examples of cases
        /// where not possible are: fields can't be created on POCOs, property values can't be set on immutable items
        /// such as anonymously typed objects).
        /// </summary>
        /// <param name="originalAction">Save, Insert, Update or Delete</param>
        /// <param name="item">item</param>
        /// <param name="connection">The connection to use</param>
        /// <param name="cancellationToken">Async <see cref="CancellationToken"/></param>
        /// <returns>The number of items affected; the modified item with PK added, if <see cref="OrmAction.Insert"/></returns>
        /// <remarks>
        /// It *is* technically possibly (by writing to private backing fields) to change the field value in anonymously
        /// typed objects - http://stackoverflow.com/a/30242237/795690 - and bizarrely VB supports writing to fields in
        /// anonymously typed objects natively even though C# doesn't - http://stackoverflow.com/a/9065678/795690 (which
        /// sounds as if it means that if this part of the library was written in VB then doing this would be officially
        /// supported? not quite sure, that assumes that the different implementations of anonymous types can co-exist)
        /// </remarks>
        private async Task <Tuple <int, object> > ActionOnItemAsync(OrmAction originalAction, object item, DbConnection connection,
                                                                    CancellationToken cancellationToken = default)
        {
            OrmAction revisedAction;
            DbCommand command = CreateActionCommand(originalAction, item, out revisedAction);

            command.Connection = connection;
            if (revisedAction == OrmAction.Insert && PrimaryKeyInfo.SequenceNameOrIdentityFunction != null)
            {
                // *All* DBs return a huge sized number for their identity by default, following Massive we are normalising to int
                var pk       = Convert.ToInt32(await ScalarAsync(command, cancellationToken).ConfigureAwait(false));
                var modified = UpsertItemPK(
                    item, pk,
                    // Don't create clone items on Save as these will then be discarded; but do still update the PK if clone not required
                    originalAction == OrmAction.Insert);
                return(new Tuple <int, object>(1, modified));
            }
            else
            {
                int n = await ExecuteAsync(command, cancellationToken).ConfigureAwait(false);

                return(new Tuple <int, object>(n, null));
            }
        }
Beispiel #4
0
 /// <summary>
 /// Perform CRUD action for the item(s) in the params list.
 /// An <see cref="IEnumerable{T}"/> of *modified* items is returned; the modification is to update the primary key to the correct new value for inserted items.
 /// If the input item does not support field writes/inserts as needed then an <see cref="ExpandoObject"/> corresponding to the updated item is returned instead.
 /// </summary>
 /// <param name="action">The ORM action</param>
 /// <param name="connection">The connection to use</param>
 /// <param name="items">The item or items</param>
 /// <returns>The list of modified items</returns>
 /// <remarks>Here and in <see cref="UpsertItemPK"/> we always return the modified original object where possible</remarks>
 internal IEnumerable <T> ActionOnItems(OrmAction action, DbConnection connection, IEnumerable <object> items)
 {
     return(ActionOnItemsWithOutput(action, connection, items).Item2);
 }
 /// <summary>
 /// Is the passed in item valid against the current validator?
 /// </summary>
 /// <param name="item">The item</param>
 /// <param name="action">Optional action type (defaults to <see cref="OrmAction.Save"/>)</param>
 /// <returns></returns>
 abstract public List <object> IsValid(object item, OrmAction action = OrmAction.Save);
Beispiel #6
0
 /// <summary>
 /// This is called one item at time, after processing for that specific item.
 /// </summary>
 /// <param name="item">The item for which the action has just been performed.
 /// The type of this is NOT normalised, and depends on what you pass in.</param>
 /// <param name="action">The ORM action</param>
 /// <returns></returns>
 virtual public void HasPerformedAction(dynamic item, OrmAction action)
 {
 }
Beispiel #7
0
 /// <summary>
 /// This is called one item at time, just before the processing for that specific item.
 /// <see cref="OrmAction"/> is performed iff this returns true. If false is returned, no processing
 /// is done for this item, but processing still continues for all remaining items.
 /// </summary>
 /// <param name="item">The item for which the action is about to be performed.
 /// The type of this is NOT normalised, and depends on what you pass in.</param>
 /// <param name="action">The ORM action</param>
 /// <returns></returns>
 virtual public bool ShouldPerformAction(dynamic item, OrmAction action)
 {
     return(true);
 }
Beispiel #8
0
 /// <summary>
 /// If prevalidation is enabled Mighty calls this one item at a time before any database actions are done;
 /// if any item fails, no actions are done for any item.
 /// This also called by the <see cref="MightyOrm"/>.IsValid method.
 /// The default implementation of this method directly calls the `Validate` method and so ignores the <paramref name="action"/> parameter,
 /// but your own override can change this.
 /// </summary>
 /// <param name="action">You can choose to ignore this and do the same validation for every action.</param>
 /// <param name="item">
 /// The item to validate. NB this can be whatever you pass in as input objects, and therefore is NOT restricted to items of the generic type
 /// even for generically typed <see cref="MightyOrm{T}"/>.
 /// Not necessarily a representation of the item for action: e.g. for delete only, it might be a representation of just the PK depending on how `Delete` was called.
 /// Despite this, you can write fairly stright-forward validators; have a look at the table classes in the Mighty docs examples.
 /// </param>
 /// <param name="reportError">
 /// Your code should call this function, e.g. <paramref name="reportError"/>("My error text") to add errors to the error list.
 /// You may choose to add strings, or a more complex object if you wish.
 /// NB Adding one or more errors indicates that the item fails, adding no errors indicates success.
 /// </param>
 /// <returns></returns>
 virtual public void ValidateForAction(OrmAction action, dynamic item, Action <object> reportError)
 {
     Validate(item, reportError);
 }
Beispiel #9
0
        /// <summary>
        /// Perform CRUD action for the item(s) in the params list.
        /// An <see cref="IEnumerable{T}"/> of *modified* items is returned; the modification is to update the primary key to the correct new value for inserted items.
        /// If the input item does not support field writes/inserts as needed then an <see cref="ExpandoObject"/> corresponding to the updated item is returned instead.
        /// </summary>
        /// <param name="action">The ORM action</param>
        /// <param name="connection">The connection to use</param>
        /// <param name="items">The item or items</param>
        /// <param name="cancellationToken">Async <see cref="CancellationToken"/></param>
        /// <returns>The list of modified items</returns>
        /// <remarks>Here and in <see cref="UpsertItemPK"/> we always return the modified original object where possible</remarks>
        internal async Task <Tuple <int, IEnumerable <T> > > ActionOnItemsWithOutputAsync(OrmAction action, DbConnection connection, IEnumerable <object> items, CancellationToken cancellationToken = default)
        {
            List <T> modifiedItems = null;

            if (action == OrmAction.Insert)
            {
                modifiedItems = new List <T>();
            }
            int count    = 0;
            int affected = 0;

            ValidateAction(items, action);
            foreach (var item in items)
            {
                if (Validator.ShouldPerformAction(item, action))
                {
                    var result = await ActionOnItemAsync(action, item, connection, cancellationToken).ConfigureAwait(false);

                    affected += result.Item1;
                    if (action == OrmAction.Insert)
                    {
                        var modified = result.Item2 ?? item;
                        if (IsGeneric && !(modified is T))
                        {
                            // create an item of type T from the modified item (e.g. a name-value dictionary/ExpandoObject)
                            modified = New(modified, false);
                        }
                        modifiedItems.Add((T)modified);
                    }
                    Validator.HasPerformedAction(item, action);
                }
                count++;
            }
            return(new Tuple <int, IEnumerable <T> >(affected, modifiedItems));
        }
Beispiel #10
0
 /// <summary>
 /// Perform CRUD action for the item(s) in the params list.
 /// An <see cref="IEnumerable{T}"/> of *modified* items is returned; the modification is to update the primary key to the correct new value for inserted items.
 /// If the input item does not support field writes/inserts as needed then an <see cref="ExpandoObject"/> corresponding to the updated item is returned instead.
 /// </summary>
 /// <param name="action">The ORM action</param>
 /// <param name="connection">The connection to use</param>
 /// <param name="items">The item or items</param>
 /// <param name="cancellationToken">Async <see cref="CancellationToken"/></param>
 /// <returns>The list of modified items</returns>
 /// <remarks>Here and in <see cref="UpsertItemPK"/> we always return the modified original object where possible</remarks>
 internal async Task <IEnumerable <T> > ActionOnItemsAsync(OrmAction action, DbConnection connection, IEnumerable <object> items, CancellationToken cancellationToken = default)
 {
     return((await ActionOnItemsWithOutputAsync(action, connection, items, cancellationToken).ConfigureAwait(false)).Item2);
 }