public EntityRecord ReadRecord(IDataRecord dataRecord, EntitySession session) { // Some outer join queries may produce entities that are null; so we first try to read Primary key values - if they're all null, we return null. if (_primaryKeyColumns.Count > 0 && PrimaryKeyIsNull(dataRecord)) return null; var entRec = new EntityRecord(_tableInfo.Entity, EntityStatus.Loading); object dbValue = null; OutColumnMapping colMap = null; //for-i loop is more efficient than foreach for (int i = 0; i < _columns.Count; i++) { try { colMap = _columns[i]; dbValue = dataRecord[colMap.ReaderColumnIndex]; //System.Diagnostics.Debug.WriteLine(colMap.DbColumn.ColumnName + " " + dbValue + "(" + dbValue.GetType() + ")"); var conv = colMap.DbColumn.TypeInfo.ColumnToPropertyConverter; if(dbValue != null && conv != null) dbValue = conv(dbValue); entRec.ValuesOriginal[colMap.DbColumn.Member.ValueIndex] = dbValue; } catch (Exception ex) { ex.AddValue("DataRecord", dataRecord); ex.AddValue("ColumnName", colMap.DbColumn.ColumnName); ex.AddValue("DbValue", dbValue); throw; } } var sessionRec = session.Attach(entRec); //might return different, previously loaded record return sessionRec; }
public CachedRecordData(EntityRecord record) { PrimaryKey = record.PrimaryKey; Values = new object[record.ValuesOriginal.Length]; Version = record.Session.Context.EntityCacheVersion; Array.Copy(record.ValuesOriginal, Values, Values.Length); }
//If record with the same PK value is already in dictionary, does not add but returns existing one. public EntityRecord Add(EntityRecord record) { var oldRec = Find(record.PrimaryKey); if (oldRec != null) return oldRec; var weakRef = new WeakReference(record); _table[record.PrimaryKey] = weakRef; return record; }
public EntityRecord Lookup(EntityKey primaryKey, EntitySession session) { var strKey = primaryKey.AsString(); var data = _cacheTable.Lookup(strKey); if(data == null) return null; var needVersion = session.Context.EntityCacheVersion; if(data.Version < needVersion) { _cacheTable.Remove(primaryKey.AsString()); return null; } var rec = new EntityRecord(primaryKey); Array.Copy(data.Values, rec.ValuesOriginal, data.Values.Length); rec.SourceCacheType = CacheType.Sparse; session.Attach(rec); return rec; }
//Copies PK values into corresponding FK public static void CopyPrimaryKeyToForeign(EntityRecord record, EntityMemberInfo entityRefMember, EntityRecord refTarget) { var refInfo = entityRefMember.ReferenceInfo; var fkMembers = refInfo.FromKey.ExpandedKeyMembers; //If target is null, set all to DbNull if (refTarget == null) { for (int i = 0; i < fkMembers.Count; i++) record.SetValueDirect(fkMembers[i].Member, DBNull.Value); return; } //refTarget is not null var pkMembers = refInfo.ToKey.ExpandedKeyMembers; for (int i = 0; i < pkMembers.Count; i++) { //copy value from PK to FK member var value = refTarget.GetValueDirect(pkMembers[i].Member); record.SetValueDirect(fkMembers[i].Member, value); } }
// Will be overridden SecureSession public virtual object RecordGetMemberValue(EntityRecord record, EntityMemberInfo member) { return(member.GetValueRef(record, member)); }
public static object GetSimpleValue(EntityRecord record, EntityMemberInfo member) { var value = record.GetValueDirect(member); if (value == null && record.Status != EntityStatus.New) { record.Reload(); value = record.GetValueDirect(member); } if (value == DBNull.Value) return null; return value; }
public static int CompareTopologicalIndexes(EntityRecord x, EntityRecord y) { var entIndexCompare = x.SortIndex.CompareTo(y.SortIndex); if (entIndexCompare != 0) return entIndexCompare; return x.SortSubIndex.CompareTo(y.SortSubIndex); }
public EntityBase(EntityRecord record) { Record = record; }
// The property on interface is not nullable (int), but the column in database is. We substitute the default value for type (0) // with DbNull.Value public static object GetValueTypeReplaceNullWithDefault(EntityRecord record, EntityMemberInfo member) { var value = GetSimpleValue(record, member); if (value == DBNull.Value) return member.DefaultValue; return value; }
object GetValue(EntityRecord record, EntityMemberInfo member) { var v = record.GetValueDirect(member); if(v != null) { if(v == DBNull.Value) return null; var rec = (EntityRecord)v; return rec.EntityInstance; } //retrieve entity var targetPk = EntityKey.CreateSafe(_targetEntity.PrimaryKey, record.PrimaryKey.Values); var targetRec = record.Session.GetRecord(targetPk); if (targetRec == null) { record.SetValueDirect(member, DBNull.Value); return null; } record.SetValueDirect(member, targetRec); if(targetRec.ByRefUserPermissions == null) targetRec.ByRefUserPermissions = member.ByRefPermissions; return targetRec.EntityInstance; }
public bool TryExecuteSelect(EntitySession session, EntityCommand command, object[] args, out IList<EntityRecord> records) { records = _empty; if(!Settings.CacheEnabled || session.CacheDisabled) return false; if (!string.IsNullOrWhiteSpace(command.Filter)) return false; var cachingType = command.TargetEntityInfo.CacheType; if(cachingType == CacheType.None) return false; switch(cachingType) { case CacheType.None: return false; case CacheType.FullSet: var start = _timeService.ElapsedMilliseconds; var result = _fullSetCache.TryExecuteSelect(session, command, args, out records); if(result) { var end = _timeService.ElapsedMilliseconds; var rowCount = records == null ? 0 : records.Count; LogCommand(session, command, args, cachingType, end - start, rowCount); } return result; case CacheType.Sparse: var getByPk = command.Kind == EntityCommandKind.SelectByKey && command.SelectKey.KeyType.IsSet(KeyType.PrimaryKey); if(getByPk) { var pk = new EntityKey(command.SelectKey, args); var rec = _sparseCache.Lookup(pk, session); if(rec != null) { records = new EntityRecord[] { rec }; LogCommand(session, command, args, cachingType, 0, 1); return true; } } return false; }//switch return false; }
void SaveEvents_SavingChanges(EntityRecord record, EventArgs args) { if(ActionType == TrackingActionType.Created && record.Status == EntityStatus.New || ActionType == TrackingActionType.Updated && (record.Status == EntityStatus.New || record.Status == EntityStatus.Modified)) { //Do it directly, to bypass authorization checks (it should still work with record.SetValue) record.ValuesModified[_member.ValueIndex] = record.Session.NextTransactionId; } }
public static void SetValueTypeReplaceDefaultWithNull(EntityRecord record, EntityMemberInfo member, object value) { if (value == member.DefaultValue) value = DBNull.Value; SetSimpleValue(record, member, value); }
//Utilities private static void MarkTargetToClearLists(EntityRecord record, EntityMemberInfo member, object newEntityRef) { //If record is not new, mark old ref to clear lists if (record.Status != EntityStatus.New) { EntityRecord oldTargetRec; var oldTarget = record.ValuesTransient[member.ValueIndex]; if(oldTarget == null) oldTargetRec = GetEntityRefTarget(record, member); else oldTargetRec = EntityHelper.GetRecord(oldTarget); if(oldTargetRec != null) oldTargetRec.MarkForClearLists(); } //Check new ref if(newEntityRef != null) { var newTargetRec = EntityHelper.GetRecord(newEntityRef); if(newTargetRec != null) newTargetRec.MarkForClearLists(); } }
public static void SetTransientValue(EntityRecord record, EntityMemberInfo member, object value) { record.ValuesTransient[member.ValueIndex] = value; }
public static void SetSimpleValue(EntityRecord record, EntityMemberInfo member, object value) { if (value == null) value = DBNull.Value; var oldValue = record.GetValueDirect(member); if (member.AreValuesEqual(oldValue, value)) return; record.SetValueDirect(member, value); if (record.Status == EntityStatus.Loaded) record.Status = EntityStatus.Modified; }
public static void SetEntityRefValue(EntityRecord record, EntityMemberInfo member, object value) { //If there's list on the other side, mark target records( old ref and new ref) to clear lists. if(member.ReferenceInfo.TargetListMember != null) MarkTargetToClearLists(record, member, value); EntityRecord newRec = null; if (value == null) value = DBNull.Value; if (value == DBNull.Value) { record.ValuesTransient[member.ValueIndex] = DBNull.Value; } else { newRec = EntityHelper.GetRecord(value); Util.Check(newRec != null, "Invalid entity ref value - not an entity: {0}", value); record.ValuesTransient[member.ValueIndex] = newRec; if(newRec.ByRefUserPermissions == null) newRec.ByRefUserPermissions = member.ByRefPermissions; } CopyPrimaryKeyToForeign(record, member, newRec); if (record.Status == EntityStatus.Loaded) record.Status = EntityStatus.Modified; }
public void Remove(EntityRecord record) { var key = record.PrimaryKey.AsString(); _cacheTable.Remove(key); }
protected void ReadCrudOutputParameterValues(IDbCommand command, DbCommandInfo commandInfo, EntityRecord record) { for (int i = 0; i < commandInfo.OutputParameters.Count; i++) { var prmInfo = commandInfo.OutputParameters[i]; var col = prmInfo.SourceColumn; if (col == null) continue; var prm = command.Parameters[prmInfo.Name] as IDbDataParameter; var value = prm.Value; var conv = prmInfo.TypeInfo.ColumnToPropertyConverter; if (value != DBNull.Value && conv != null) value = conv(value); record.ValuesModified[col.Member.ValueIndex] = value; }//for }
public virtual void RecordSetMemberValue(EntityRecord record, EntityMemberInfo member, object value) { member.SetValueRef(record, member, value); }
private void SetCrudCommandParameterValues(DbCommandInfo commandInfo, IDbCommand command, EntityRecord record) { if (record.Status == EntityStatus.Stub) record.Reload(); for (int i = 0; i < commandInfo.Parameters.Count; i++) { var prm = (IDbDataParameter)command.Parameters[i]; prm.Value = DBNull.Value; var prmInfo = commandInfo.Parameters[i]; var isInput = prmInfo.Direction == ParameterDirection.Input || prmInfo.Direction == ParameterDirection.InputOutput; if (!isInput) continue; var col = prmInfo.SourceColumn; if (col == null || col.Member == null) continue; var value = record.GetValueDirect(col.Member); if(value == null) value = DBNull.Value; var conv = prmInfo.TypeInfo.PropertyToColumnConverter; if (value != DBNull.Value && conv != null) value = conv(value); prm.Value = value; } //for i }
public EntityKey(EntityKeyInfo keyInfo, EntityRecord record) { KeyInfo = keyInfo; Values = new object[KeyInfo.ExpandedKeyMembers.Count]; CopyValues(record); }
public static object GetTransientValue(EntityRecord record, EntityMemberInfo member) { return record.ValuesTransient[member.ValueIndex]; }
internal DbCommandInfo GetDbCommandForSave(EntityRecord record) { var crud = record.EntityInfo.CrudCommands; EntityCommand entCmd; switch (record.Status) { case EntityStatus.New: entCmd = crud.Insert; break; case EntityStatus.Modified: entCmd = crud.Update; break; case EntityStatus.Deleting: entCmd = crud.Delete; break; default: return null; } var cmdInfo = GetDbCommandInfo(entCmd); return cmdInfo; }
public static object DummyGetValue(EntityRecord record, EntityMemberInfo member) { return null; }
private void ApplyUpdate(DataConnection connection, EntityRecord record) { var cmdInfo = GetDbCommandForSave(record); Util.Check(cmdInfo != null, "Failed to find update/insert/delete command for entity {0}, status {1).", record.EntityInfo.Name, record.Status); try { var cmd = CreateDbCommand(cmdInfo, connection); SetCrudCommandParameterValues(cmdInfo, cmd, record); ExecuteDbCommand(cmd, connection, DbExecutionType.NonQuery); if(cmdInfo.PostUpdateActions.Count > 0) foreach(var action in cmdInfo.PostUpdateActions) action(connection, cmd, record); record.SubmitCount++; record.EntityInfo.SaveEvents.OnSubmittedChanges(record); } catch(Exception ex) { ex.AddValue("entity-command-name", cmdInfo.EntityCommand.CommandName); ex.AddValue("record", record); throw; } }
public static void DummySetValue(EntityRecord record, EntityMemberInfo member, object value) { }
private bool ShouldUpdate(EntityRecord record) { if (record.Status == EntityStatus.Modified && record.EntityInfo.Flags.IsSet(EntityFlags.NoUpdate)) return false; //if for whatever reason we have such a record, just ignore it if(record.Status == EntityStatus.Fantom) return false; return true; }
// When we get the value, if it is null, we must try to load the list public static object GetEntityListValue(EntityRecord record, EntityMemberInfo member) { var list = record.ValuesTransient[member.ValueIndex]; if (list != null) return list; //create new list list = record.InitChildEntityList(member); return list; }
void SetValue(EntityRecord record, EntityMemberInfo member, object value) { Util.Throw("Back-ref properties are readonly, cannot set value. Property: {0}.{1}", member.Entity.Name, member.MemberName); }
private void AddRecordUpdateToBatch(EntityRecord rec) { CheckCurrentCommand(); var dbCmd = _currentCommand.DbCommand; var argValues = new List<string>(); var cmdInfo = _db.GetDbCommandForSave(rec); foreach (var prmInfo in cmdInfo.Parameters) { var col = prmInfo.SourceColumn; //Check if we need to use already defined parameter; // this happens when we insert parent and child records with parent having identity primary key column if (_updateSet.UsesOutParams && col != null && col.Flags.IsSet(DbColumnFlags.IdentityForeignKey)) { //Find out parameter that returns the identity of the parent record var parentRec = rec.GetValueDirect(col.Member.ForeignKeyOwner) as EntityRecord; if (parentRec != null && parentRec.CustomTag != null) { //parentRec has identity PK, and is already in _identities list var idSource = (IdentitySource) parentRec.CustomTag; if (idSource.BatchCommand == _currentCommand) argValues.Add(idSource.Parameter.ParameterName); //if it is the same command, just add ref to parameter else { //different command - create new parameter, and add action to copy param value from source // dbCmd.Parameters.Add(idSource.Parameter); //this does not work - parameters cannot be shared between commands var dbParam = _driver.AddParameter(dbCmd, prmInfo); //override parameter name dbParam.ParameterName = _driver.DynamicSqlParameterPrefix + "P" + (dbCmd.Parameters.Count - 1); argValues.Add(dbParam.ParameterName); var sourcePrm = idSource.Parameter; idSource.BatchCommand.AddPostAction(() => dbParam.Value = sourcePrm.Value); } continue; //next param } }//if //Get the value, analyze it, see if it is ok to use literal or it's better to put the value into parameter var value = rec.GetValueDirect(col.Member); if (value == null) value = DBNull.Value; var conv = prmInfo.TypeInfo.PropertyToColumnConverter; if (value != DBNull.Value && conv != null) value = conv(value); if (BatchShouldUseParameterFor(prmInfo, value)) { //create parameter var dbParam = _driver.AddParameter(dbCmd, prmInfo); //override parameter name dbParam.ParameterName = _driver.DynamicSqlParameterPrefix + "P" + (dbCmd.Parameters.Count - 1); dbParam.Value = value; //If it is parameter holding identity returned from stored proc, then save its info in the rec.CustomTag bool isIdentityOut = rec.Status == EntityStatus.New && col.Flags.IsSet(DbColumnFlags.Identity) && dbParam.Direction == ParameterDirection.Output; if (isIdentityOut) rec.CustomTag = new IdentitySource() { BatchCommand = _currentCommand, Parameter = dbParam}; //add reference to parameter in arg list var strArg = dbParam.ParameterName; if (dbParam.Direction != ParameterDirection.Input) { strArg = string.Format(_driver.CommandCallOutParamFormat, strArg); //copy value returned from sp into entity property _currentCommand.AddPostAction(() => rec.SetValueDirect(col.Member, dbParam.Value) ); } argValues.Add(strArg); } else { string argValue; if (value == DBNull.Value) argValue = "NULL"; else argValue = prmInfo.TypeInfo.ToLiteral(value); argValues.Add(argValue); }// if BatchShouldUseParameterFor }//foreach prm //format method call var strArgs = string.Join(", ", argValues); var strCall = string.Format(_driver.CommandCallFormat, cmdInfo.FullCommandName, strArgs); //append it to sql _sqlBuilder.AppendLine(strCall); }
private static bool UsesOutParam(EntityRecord record) { var flags = record.EntityInfo.Flags; return flags.IsSet(EntityFlags.HasRowVersion) || (flags.IsSet(EntityFlags.HasIdentity) && record.Status == EntityStatus.New); }
public void RegisterForClearLists(EntityRecord record) { // may need some concurrency safety (for m-threaded session) this.RecordsToClearLists.Add(record); }
public PropertyBoundListManyToOne(EntityRecord ownerRecord, EntityMemberInfo ownerMember) : base(ownerRecord, ownerMember) { }
public void Add(EntityRecord record) { var data = new CachedRecordData(record); var key = record.PrimaryKey.AsString(); _cacheTable.Add(key, data); }