/// <summary> /// Generates a delete core command for the given entity, or returns null if such /// command cannot be generated for whatever reasons. /// </summary> internal static IDeleteCommand GenerateDeleteCommand(this IUberMap map, object entity) { if (entity == null) { return(null); } if (map == null || map.IsDisposed || !map.IsValidated) { return(null); } IDeleteCommand cmd = null; MetaEntity meta = MetaEntity.Locate(entity, create: true); if (meta.Record == null) { var record = new Core.Concrete.Record(map.Schema); map.WriteRecord(entity, record); meta.Record = record; } var id = map.ExtractId(meta.Record); if (id != null) { cmd = map.Link.Engine.CreateDeleteCommand(map.Link, x => map.Table); if (map.Discriminator != null) { cmd.Where(map.Discriminator); } var tag = new DynamicNode.Argument("x"); for (int i = 0; i < id.Count; i++) { var left = new DynamicNode.GetMember(tag, id.Schema[i].ColumnName); var bin = new DynamicNode.Binary(left, ExpressionType.Equal, id[i]); cmd.Where(x => bin); left.Dispose(); bin.Dispose(); } tag.Dispose(); id.Dispose(); } return(cmd); }
/// <summary> /// Validates that the row version captured in the meta-entity is the same as the current /// one in the database, throwing an exception if a change is detected. /// </summary> internal static void ValidateRowVersion(this MetaEntity meta) { var entity = meta.Entity; if (entity == null) { return; } if (meta.UberMap == null) { return; } if (meta.Record == null) { return; } var vc = meta.UberMap.VersionColumn; if (vc.Name == null) { return; } // Getting the most updated record, if any... var cmd = meta.UberMap.Link.From(x => meta.UberMap.Table); var tag = new DynamicNode.Argument("x"); var id = meta.UberMap.ExtractId(meta.Record); if (id == null) { throw new InvalidOperationException( "Cannot obtain identity from entity '{0}'".FormatWith(meta)); } for (int i = 0; i < id.Count; i++) { var left = new DynamicNode.GetMember(tag, id.Schema[i].ColumnName); var bin = new DynamicNode.Binary(left, ExpressionType.Equal, id[i]); cmd.Where(x => bin); bin.Dispose(); left.Dispose(); } id.Dispose(); tag.Dispose(); var rec = (IRecord)cmd.First(); cmd.Dispose(); if (rec == null) { return; } // Comparing values.... string captured = vc.ValueToString == null ? meta.Record[vc.Name].Sketch() : vc.ValueToString(meta.Record[vc.Name]); string current = vc.ValueToString == null ? rec[vc.Name].Sketch() : vc.ValueToString(rec[vc.Name]); if (string.Compare(captured, current) != 0) { throw new ChangedException( "Captured version '{0}' for entity '{1}' differs from the database's current one '{2}'." .FormatWith(captured, meta, current)); } }
/// <summary> /// Generates an update core command for the given entity, or returns null if such /// command cannot be generated for whatever reasons. /// </summary> internal static IUpdateCommand GenerateUpdateCommand(this IUberMap map, object entity) { if (entity == null) { return(null); } if (map == null || map.IsDisposed || !map.IsValidated) { return(null); } IUpdateCommand cmd = null; MetaEntity meta = MetaEntity.Locate(entity, create: true); if (meta.Record == null) { var record = new Core.Concrete.Record(map.Schema); map.WriteRecord(entity, record); meta.Record = record; } var changes = meta.GetRecordChanges(); if (changes == null) { return(null); } var num = changes.Schema.Count(x => !x.IsReadOnlyColumn); if (num != 0) { var id = map.ExtractId(meta.Record); if (id != null) { cmd = map.Link.Engine.CreateUpdateCommand(map.Link, x => map.Table); if (map.Discriminator != null) { cmd.Where(map.Discriminator); } var tag = new DynamicNode.Argument("x"); for (int i = 0; i < id.Count; i++) { var left = new DynamicNode.GetMember(tag, id.Schema[i].ColumnName); var bin = new DynamicNode.Binary(left, ExpressionType.Equal, id[i]); cmd.Where(x => bin); left.Dispose(); bin.Dispose(); } for (int i = 0; i < changes.Count; i++) { if (changes.Schema[i].IsReadOnlyColumn) { continue; } var node = new DynamicNode.SetMember(tag, changes.Schema[i].ColumnName, changes[i]); cmd.Columns(x => node); node.Dispose(); } tag.Dispose(); id.Dispose(); } } changes.Dispose(disposeSchema: true); return(cmd); }