public static object NextSkippingSentinel([NotNull] this ValueGenerator valueGenerator, [NotNull] IProperty property)
        {
            var value = valueGenerator.Next();

            if (property.IsSentinelValue(value))
            {
                value = valueGenerator.Next();
            }

            return(value);
        }
Пример #2
0
        /// <summary>
        /// Updates the database-generated properties for <paramref name="internalEntityEntry"/>.
        /// </summary>
        /// <param name="internalEntityEntry">The <see cref="IUpdateEntry"/> the <see cref="IUpdateEntry"/> representing the document being updated.</param>
        protected void UpdateDbGeneratedProperties(InternalEntityEntry internalEntityEntry)
        {
            var entityEntry = internalEntityEntry.ToEntityEntry();

            foreach (IProperty property in _dbGeneratedProperties)
            {
                ValueGenerator valueGenerator   = _valueGeneratorSelector.Select(property, internalEntityEntry.EntityType);
                object         dbGeneratedValue = valueGenerator.Next(entityEntry);
                internalEntityEntry.SetProperty(property, dbGeneratedValue, true);
                property.GetSetter().SetClrValue(internalEntityEntry.Entity, dbGeneratedValue);
            }
        }
Пример #3
0
 public static Guid NewSquentialGuid()
 {
     return(_generator.Next(null));
 }
        public override Identifier Next(EntityEntry entry)
        {
            Identifier id = new Identifier(_valueGenerator.Next(entry));

            return(id);
        }
Пример #5
0
        /// <summary>
        ///     Initializes a new instance of the <see cref="SaveChangesHelper" /> class.
        /// </summary>
        /// <param name="dbContext"> <see cref="DbContext" /> against which the requested query will be executed. </param>
        /// <param name="request"> The <see cref="SaveChangesRequest" /> object from the client containing the updated entities. </param>
        public SaveChangesHelper(DbContext dbContext, SaveChangesRequest request)
        {
            this.dbContext = dbContext;

            var typeMap                  = this.dbContext.Model.GetEntityTypes().ToDictionary(x => x.DisplayName());
            var stateManager             = this.dbContext.GetService <IStateManager>();
            var entityMaterializerSource = this.dbContext.GetService <IEntityMaterializerSource>();

            // Materialize entities and add entries to dbContext
            EntityEntry MaterializeAndTrackEntity(UpdateEntryDto dto)
            {
                IEntityType entityType = typeMap[dto.EntityTypeName];

                object MaterializeEntity()
                {
                    var valueBuffer            = new ValueBuffer(dto.GetCurrentValues(entityType, request.Mapper));
                    var materializationContext = new MaterializationContext(valueBuffer, this.dbContext);

                    return(entityMaterializerSource.GetMaterializer(entityType).Invoke(materializationContext));
                }

                EntityEntry entry;

                if (entityType.HasDefiningNavigation())
                {
                    IKey     key       = entityType.DefiningEntityType.FindPrimaryKey();
                    object[] keyValues = dto.GetDelegatedIdentityKeys(request.Mapper, key);

                    // Here we assume that the owner entry is already present in the context
                    EntityEntry ownerEntry = stateManager.TryGetEntry(key, keyValues).ToEntityEntry();

                    ReferenceEntry referenceEntry = ownerEntry.Reference(entityType.DefiningNavigationName);
                    if (referenceEntry.CurrentValue == null)
                    {
                        referenceEntry.CurrentValue = MaterializeEntity();
                    }

                    entry = referenceEntry.TargetEntry;
                }
                else
                {
                    entry = stateManager.GetOrCreateEntry(MaterializeEntity()).ToEntityEntry();
                }

                // Correlate properties of DTO and entry
                var props = dto.JoinScalarProperties(entry, request.Mapper);

                // Set Key properties
                foreach (var p in props.Where(x => x.EfProperty.Metadata.IsKey()))
                {
                    p.EfProperty.CurrentValue = p.CurrentValue;
                    if (p.EfProperty.Metadata.GetOriginalValueIndex() >= 0)
                    {
                        p.EfProperty.OriginalValue = p.OriginalValue;
                    }
                }

                // Set EntityState after PK values (temp or perm) are set.
                // This will add entities to identity map.
                entry.State = dto.EntityState;

                // Set non key properties
                foreach (var p in props.Where(x => !x.EfProperty.Metadata.IsKey()))
                {
                    bool canSetCurrentValue =
                        p.EfProperty.Metadata.IsShadowProperty ||
                        p.EfProperty.Metadata.TryGetMemberInfo(forConstruction: false, forSet: true, out _, out _);

                    if (canSetCurrentValue)
                    {
                        p.EfProperty.CurrentValue = p.CurrentValue;
                    }

                    if (p.EfProperty.Metadata.GetOriginalValueIndex() >= 0 &&
                        p.EfProperty.OriginalValue != p.OriginalValue)
                    {
                        p.EfProperty.OriginalValue = p.OriginalValue;
                    }

                    if (canSetCurrentValue)
                    {
                        p.EfProperty.IsModified = p.DtoProperty.IsModified;
                    }
                }

                // Mark temporary property values
                foreach (var p in props.Where(x => x.DtoProperty.IsTemporary))
                {
                    p.EfProperty.IsTemporary = true;
                }

                return(entry);
            }

            request.SharedIdentityDataTransferObjects.ForEach(dto => MaterializeAndTrackEntity(dto));
            var entries = request.DataTransferObjects.Select(MaterializeAndTrackEntity).ToList();

            // Replace temporary PKs coming from client with generated values (e.g. HiLoSequence)
            var valueGeneratorSelector = this.dbContext.GetService <IValueGeneratorSelector>();

            foreach (EntityEntry entry in entries)
            {
                foreach (PropertyEntry tempPk in
                         entry.Properties.Where(p =>
                                                p.IsTemporary &&
                                                p.Metadata.IsKey() &&
                                                p.Metadata.RequiresValueGenerator()).ToList())
                {
                    ValueGenerator valueGenerator = valueGeneratorSelector.Select(tempPk.Metadata, entry.Metadata);
                    if (!valueGenerator.GeneratesTemporaryValues)
                    {
                        tempPk.CurrentValue = valueGenerator.Next(entry);
                        tempPk.IsTemporary  = false;
                    }
                }
            }

            this.Entries = entries.Select(e => e.GetInfrastructure()).ToList();
        }