private bool ShouldUpdateColumn <TDbEntity, TId>( ref DbValue <TId> column, TId value, ref IDbEntityRef <TDbEntity> dbEntityRef, Func <long> getValueAsLongOrZero) where TDbEntity : DbEntity { if (EqualityComparer <TId> .Default.Equals(column.Entity, value)) { return(false); } if (!_allowSettingColumns) { var writeDb = _db as WriteDb; if (writeDb != null && writeDb.Settings.ReturnPreviouslyLoadedEntity_Obsolete) { if (column.ValueWasAssigned() || (dbEntityRef != null && dbEntityRef.HasAssignedValue)) { // we do not want to modify updated entities by returning them again with a query return(false); } } throw new InvalidOperationException( "Review your query. It smells wrong! Most probably you used UnionDb() with queries that have different columns."); } if (dbEntityRef != null) { if (dbEntityRef is DbEntityRefCached <TDbEntity> ) { dbEntityRef = GlobalDbConfiguration.GetConfigurationOrEmpty(GetType()).CacheService.GetDbEntityRefCached <TDbEntity>((int)getValueAsLongOrZero()); } else { dbEntityRef.ResetValue(); } } return(true); }
protected IDbEntityRef <TMember> GetDbEntityRef <TMember>( bool isForeignKey, string[] idColumnNames, Func <long?>[] entityIds, Action <TMember> beforeRightsCheckAction) where TMember : DbEntity { IDbEntityRef <TMember> dbEntityRef = null; if (_getChildrenFromCache && entityIds.Length == 1) { var entityId = entityIds[0](); if (entityId.HasValue) { if (idColumnNames.Length != 1 || idColumnNames[0] != "[Id]") { throw new InvalidOperationException("Getting the reference by foreign key is broken. If you get here, this is probably a follow up problem because of an error that happened earlier."); } if (typeof(IId).IsAssignableFrom(typeof(TMember)) && entityId.Value <= int.MaxValue) { dbEntityRef = GlobalDbConfiguration.GetConfigurationOrEmpty(GetType()).CacheService.GetDbEntityRefCached <TMember>((int)entityId.Value); } } else { return(null); } } if (dbEntityRef == null) { dbEntityRef = new DbEntityRef <TMember>(DbInternal, isForeignKey, idColumnNames, entityIds, _lazyLoadChildren, _getChildrenFromCache); } return(dbEntityRef); }
protected void UpdateColumnIfDifferent <TDbEntity, TId>(ref DbValue <TId?> column, TId?value, ref IDbEntityRef <TDbEntity> dbEntityRef) where TDbEntity : DbEntity where TId : struct { if (ShouldUpdateColumn(ref column, value, ref dbEntityRef, () => (value as long?) ?? 0)) { column.Entity = value; } }
/// <summary> /// DbEntity Assignment /// </summary> /// <typeparam name="TEntityToSet">Type of entity to assign ("Item" if i set ItemProduct.Item)</typeparam> /// <typeparam name="TThisEntity">Type of this entity entity ("ItemProduct" if i set ItemProduct.Item)</typeparam> /// <param name="newValue">This entity gets assigned to the object (righthand side of the =)</param> /// <param name="newValueId">Id or Null of newValue</param> /// <param name="reference">This newValue gets assigned to this object (lefthand side of the =)</param> /// <param name="referenceIdSetter"></param> /// <param name="otherSideSet"></param> /// <param name="setOtherSideEntity">Method to be applied on the new value</param> /// <param name="idChangedAction">Method to be applied if id Changed</param> /// <param name="referenceIdValue"></param> protected void AssignDbEntity <TEntityToSet, TThisEntity>( TEntityToSet newValue, long?[] newValueId, IDbEntityRef <TEntityToSet> reference, long?[] referenceIdValue, Action <long?>[] referenceIdSetter, Func <TEntityToSet, IDbEntitySet <TThisEntity> > otherSideSet, Action <TEntityToSet, TThisEntity> setOtherSideEntity, EventHandler idChangedAction) where TEntityToSet : DbEntity where TThisEntity : DbEntity { if (!_lazyLoadChildren && newValue != null && newValue._lazyLoadChildren) { throw new InvalidOperationException($"Lazy loading of {typeof(TEntityToSet).Name} is disabled, so is the assignment"); } if (newValue != null && !newValue._lazyLoadChildren && _lazyLoadChildren) { throw new InvalidOperationException( "Cannot assign an entity of type {typeof(TEntityToSet).Name} which has _lazyLoadChildren == false"); } TEntityToSet previousValue = (reference.HasLoadedValue || reference.HasAssignedValue) ? reference.GetEntity(null) : null; // 2TK BDA INotifyDeveloper Event o.Ä //#if DEBUG // if (WarnDeveloperIfEntitiesAlreadyConnected // && MachineInfo.IsDevelopmentMachine // && previousValue != null // && !ReferenceEquals(previousValue, newValue)) // { // if (Debugger.IsAttached) // { // // Entity ist bereits da. Es wurde bereits vorher zugegriffen was nicht gut ist // Debugger.Break(); // } // } //#endif var idEntity = previousValue as ILongId; var newIdEntity = newValue as ILongId; if (previousValue != null && newValue != null && idEntity != null && newValue != null && (((idEntity).Id > 0 && (idEntity).Id == (newIdEntity)?.Id) || // Entity from the database; even if it is loaded again, we assume it is the same ((idEntity).Id == 0 && ReferenceEquals(previousValue, newValue)))) // Newly created entity { return; } var referenceIsForeignKey = ((IDbEntityRefInternal)reference).IsForeignKey; // Special case. Entity is explicitly set to null (we must know that the entity was set) if (!reference.HasLoadedValue && !reference.HasAssignedValue && newValue == null) { reference.SetEntity(null); if (referenceIsForeignKey) { for (int i = 0; i < referenceIdValue.Length; i++) { if (referenceIdValue[i].HasValue) { // In order that IdChanged() or similar events are called, we assign the property instead of directly the referenceIdValue referenceIdSetter[i](null); } } } return; } // Special case. Foreign key set to null for 1-1 relations if ((reference.HasLoadedValue || reference.HasAssignedValue) && newValue == null && !referenceIsForeignKey && !ReferenceEquals(previousValue, newValue) && otherSideSet == null) { if (setOtherSideEntity != null) { setOtherSideEntity(previousValue, null); } reference.SetEntity(null); return; } // 1-N relations if (!ReferenceEquals(previousValue, newValue) || (otherSideSet != null && (!(reference.HasLoadedValue || reference.HasAssignedValue)))) { if (otherSideSet != null && previousValue != null /* && !reference.HasAssignedValue*/) { reference.SetEntity(null); otherSideSet(previousValue).Remove(this as TThisEntity); if (idChangedAction != null) { previousValue.IdChanged -= idChangedAction; } } bool loadReference = isLoaded && newValue != null && reference.HasLoadedValue == false && reference.HasAssignedValue == false; if (loadReference) { for (int i = 0; i < referenceIdValue.Length; i++) { if (referenceIdValue[i] != newValueId[i]) { loadReference = false; break; } } if (loadReference) { reference.Load(newValue); if (newValue != null && newValue._lazyLoadChildren) { if (otherSideSet != null) { var otherSide = otherSideSet(newValue); if (otherSide is DbEntitySet <TThisEntity> && ((DbEntitySet <TThisEntity>)otherSide).lazyLoadValues) { otherSide.Add(this as TThisEntity); } } else if (setOtherSideEntity != null) { setOtherSideEntity(newValue, (TThisEntity)this); } } } } if (!loadReference) { // Only update the referenceId if this entity was not loaded from the DB // or when it is no primary key, or when the referenceId is set to null (i.e. the other item is going to be deleted) // or the opposite: referenceId is currently null and is now set to another value // added && referenceIsForeignKey because of illegal set action to null to parent entity (child was set to null) if ((newValue == null && referenceIsForeignKey) || referenceIdValue[0] == null || (newValue != null && (!isLoaded || referenceIsForeignKey))) { for (int i = 0; i < referenceIdSetter.Length; i++) { // In order that IdChanged() or similar events are called, we assign the property instead of directly the referenceIdValue // Set the id explicitly to 0 (zero), such that e.g. InvoicingId.HasValue returns true, so by looking at InvoicingId you know that Invoicoing was set to an instance referenceIdSetter[i](newValue == null ? null : newValueId[i]); // referenceIdSetter[i](newValue == null || newValueId[i] == 0 ? null : newValueId[i]); } } if (newValue != null && ((!reference.HasLoadedValue && !reference.HasAssignedValue) || reference.GetEntity(null) == null || ((ILongId)reference.GetEntity(null)).Id != ((ILongId)newValue).Id) || (newValue == null && reference.GetEntity(null) != null)) { reference.SetEntity(newValue); if (newValue != null) { if (otherSideSet != null) { var otherSide = otherSideSet(newValue); if (otherSide is DbEntitySet <TThisEntity> && ((DbEntitySet <TThisEntity>)otherSide).lazyLoadValues && (!isLoaded || previousValue != null || reference.HasAssignedValue)) { otherSide.Add(this as TThisEntity); } } else if (setOtherSideEntity != null) { if (previousValue != null && !referenceIsForeignKey && !ReferenceEquals(previousValue, newValue) && otherSideSet == null) { setOtherSideEntity(previousValue, null); } setOtherSideEntity(newValue, (TThisEntity)this); } if (idChangedAction != null) { newValue.IdChanged += idChangedAction; } } } } } }
public void ProcessAssociation(DbEntity parentEntity, IDbEntityRef dbEntityRef) => ProcessAssociation(parentEntity, (IDbEntityRefInternal)dbEntityRef);