File: ObjectStateEntryOriginalDbUpdatableDataRecord.cs

package info (click to toggle)
mono 6.12.0.199%2Bdfsg-6
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 1,296,836 kB
  • sloc: cs: 11,181,803; xml: 2,850,076; ansic: 699,709; cpp: 123,344; perl: 59,361; javascript: 30,841; asm: 21,853; makefile: 20,405; sh: 15,009; python: 4,839; pascal: 925; sql: 859; sed: 16; php: 1
file content (134 lines) | stat: -rw-r--r-- 7,253 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//---------------------------------------------------------------------
// <copyright file="ObjectStateEntryOriginalDbUpdatableDataRecord.cs" company="Microsoft">
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// @owner       Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------
using System;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Data.Metadata.Edm;
using System.Diagnostics;
using System.Reflection;

namespace System.Data.Objects
{
    // Internal version of writeable original values record is used by all internal operations that need to set original values, such as PreserveChanges queries
    // This version should never be returned to the user, because it doesn't enforce any necessary restrictions.
    // See ObjectStateEntryOriginalDbUpdatableDataRecord_Public for user scenarios.
    internal class ObjectStateEntryOriginalDbUpdatableDataRecord_Internal : OriginalValueRecord
    {
        internal ObjectStateEntryOriginalDbUpdatableDataRecord_Internal(EntityEntry cacheEntry, StateManagerTypeMetadata metadata, object userObject)
            : base(cacheEntry, metadata, userObject)
        {
            EntityUtil.CheckArgumentNull(cacheEntry, "cacheEntry");
            EntityUtil.CheckArgumentNull(userObject, "userObject");
            EntityUtil.CheckArgumentNull(metadata, "metadata");
            Debug.Assert(!cacheEntry.IsKeyEntry, "Cannot create an ObjectStateEntryOriginalDbUpdatableDataRecord_Internal for a key entry");
            switch (cacheEntry.State)
            {
                case EntityState.Unchanged:
                case EntityState.Modified:
                case EntityState.Deleted:
                    break;
                default:
                    Debug.Assert(false, "An OriginalValueRecord cannot be created for an object in an added or detached state.");
                    break;
            }
        }
        protected override object GetRecordValue(int ordinal)
        {
            Debug.Assert(!_cacheEntry.IsRelationship, "should not be relationship");
            return (_cacheEntry as EntityEntry).GetOriginalEntityValue(_metadata, ordinal, _userObject, ObjectStateValueRecord.OriginalUpdatableInternal);
        }
        protected override void SetRecordValue(int ordinal, object value)
        {
            Debug.Assert(!_cacheEntry.IsRelationship, "should not be relationship");
            (_cacheEntry as EntityEntry).SetOriginalEntityValue(_metadata, ordinal, _userObject, value);
        }
    }

    // Public version of writable original values record that is to be returned to the user for setting original values directly.
    // Although this class is actually internal, it is the version that implements the writeable original values functionality returned through the public surface.
    // This version must maintain information about the index of the top-level entity property that corresponds to this record, because the record
    // may represent a complex type somewhere in an entity hierarchy and this is the only way we know which entity property it is associated with.
    // This version also does minimal necessary validation on the values that the user is trying to set.
    internal sealed class ObjectStateEntryOriginalDbUpdatableDataRecord_Public : ObjectStateEntryOriginalDbUpdatableDataRecord_Internal
    {
        // Will be EntityEntry.s_EntityRoot for entities and for complex types will be the index of the top-level entity property related to this complex type
        int _parentEntityPropertyIndex;

        internal ObjectStateEntryOriginalDbUpdatableDataRecord_Public(EntityEntry cacheEntry, StateManagerTypeMetadata metadata, object userObject, int parentEntityPropertyIndex)
            : base(cacheEntry, metadata, userObject)
        {
            _parentEntityPropertyIndex = parentEntityPropertyIndex;
        }

        protected override object GetRecordValue(int ordinal)
        {
            Debug.Assert(!_cacheEntry.IsRelationship, "should not be relationship");
            return (_cacheEntry as EntityEntry).GetOriginalEntityValue(_metadata, ordinal, _userObject, ObjectStateValueRecord.OriginalUpdatablePublic, GetPropertyIndex(ordinal));
        }

        protected override void SetRecordValue(int ordinal, object value)
        {
            StateManagerMemberMetadata member = _metadata.Member(ordinal);

            // We do not allow setting complex properties through writeable original values.
            // Instead individual scalar properties can be set on a data record that represents the complex type.
            if (member.IsComplex)
            {
                throw EntityUtil.SetOriginalComplexProperties(member.CLayerName);
            }

            // Null values are represented in data records as DBNull.Value, so translate appropriately
            object fieldValue = value ?? DBNull.Value;

            EntityEntry entry = _cacheEntry as EntityEntry;
            EntityState oldState = entry.State;

            // Only update the original values if the new value is different from the value currently set on the entity
            if (entry.HasRecordValueChanged(this, ordinal, fieldValue))
            {
                // Since the original value is going to be set, validate that is doesn't violate any restrictions

                // Throw if trying to change the original value of the primary key
                if (member.IsPartOfKey)
                {
                    throw EntityUtil.SetOriginalPrimaryKey(member.CLayerName);
                }

                // Verify non-nullable EDM members are not being set to null
                // Need to continue allowing CLR reference types to be set to null for backwards compatibility
                Type memberClrType = member.ClrType;
                if ((object)DBNull.Value == fieldValue &&
                    memberClrType.IsValueType &&
                    !member.CdmMetadata.Nullable)
                {
                    // Throw if the underlying CLR type of this property is not nullable, and it is being set to null
                    throw EntityUtil.NullOriginalValueForNonNullableProperty(member.CLayerName, member.ClrMetadata.Name, member.ClrMetadata.DeclaringType.FullName);
                }

                base.SetRecordValue(ordinal, value);

                // Update the state of the ObjectStateEntry if it has been marked as Modified
                if (oldState == EntityState.Unchanged && entry.State == EntityState.Modified)
                {
                    entry.ObjectStateManager.ChangeState(entry, oldState, EntityState.Modified);
                }

                // Set the individual property to modified
                entry.SetModifiedPropertyInternal(GetPropertyIndex(ordinal));
            }
        }

        // For entities the property index is the specified ordinal, but otherwise it's the top-level entity property index that we have saved
        private int GetPropertyIndex(int ordinal)
        {
            return _parentEntityPropertyIndex == EntityEntry.s_EntityRoot ? ordinal : _parentEntityPropertyIndex;
        }
    }
}