using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using Signum.Entities;
using Signum.Engine;
using Signum.Utilities;
using Signum.Engine.Properties;
using Signum.Entities.Reflection;
namespace Signum.Engine.Maps
{
public class Forbidden: HashSet<IdentifiableEntity>
{
internal static readonly Forbidden None = new Forbidden();
public IdentifiableEntity Filter(IdentifiableEntity ei)
{
return Contains(ei) ? null : ei;
}
}
public partial class Table
{
public SqlPreCommand Save(IdentifiableEntity ident, Forbidden forbidden)
{
var collectionFields = Fields.Values.OfType<CollectionField>();
SqlPreCommand entity = ident.IsNew ? InsertSql(ident, forbidden, false) : UpdateSql(ident, forbidden);
SqlPreCommand cols = collectionFields.Select(c => c.RelationalTable.RelationalInserts((Modifiable)c.Getter(ident), forbidden)).Combine(Spacing.Double);
ident.Modified = forbidden.Count > 0;
return SqlPreCommand.Combine(Spacing.Double, entity, cols);
}
internal SqlPreCommand InsertSql(IdentifiableEntity ident, Forbidden forbidden, bool simple)
{
Entity ent = ident as Entity;
if (ent != null)
ent.Ticks = Transaction.StartTime.Ticks;
List<SqlParameter> parameters = new List<SqlParameter>();
Fields.Values.ForEach(v => v.CreateParameter(parameters, v.Getter(ident), forbidden));
return Identity && ! simple? SqlBuilder.InsertSaveID(Name, parameters, ident) :
SqlBuilder.Insert(Name, parameters);
}
internal SqlPreCommand UpdateSql(IdentifiableEntity ident, Forbidden forbidden)
{
if (ident is Entity)
{
Entity entity = (Entity)ident;
long oldTicks = entity.Ticks;
entity.Ticks = Transaction.StartTime.Ticks;
List<SqlParameter> parameters = new List<SqlParameter>();
Fields.ForEach(c => c.Value.CreateParameter(parameters, c.Value.Getter(entity), forbidden));
return SqlBuilder.UpdateSetIdEntity(Name, parameters, entity.id, oldTicks);
}
else
{
List<SqlParameter> parameters = new List<SqlParameter>();
Fields.ForEach(c => c.Value.CreateParameter(parameters, c.Value.Getter(ident), forbidden));
return SqlBuilder.UpdateSetId(Name, parameters, ident.id);
}
}
}
public partial class RelationalTable
{
internal SqlPreCommand RelationalInserts(Modifiable collection, Forbidden forbidden)
{
if (collection == null)
return SqlBuilder.RelationalDeleteScope(Name, BackReference.Name);
if (!collection.Modified) // no es modificado ??
return null;
collection.Modified = forbidden.Count > 0;
var clean = SqlBuilder.RelationalDeleteScope(Name, BackReference.Name);
var inserts = ((IEnumerable)collection).Cast<object>()
.Where(o => (o as IdentifiableEntity).TryCS(e => !forbidden.Contains(e)) ?? true)
.Select(o => SqlBuilder.RelationalInsertScope(Name, BackReference.Name,
new List<SqlParameter>().Do(lp => Field.CreateParameter(lp, o, forbidden))))
.Combine(Spacing.Simple);
return SqlPreCommand.Combine(Spacing.Double, clean, inserts);
}
}
public abstract partial class Field
{
protected internal virtual void CreateParameter(List<SqlParameter> parameters, object value, Forbidden forbidden) { }
}
public partial class PrimaryKeyField
{
protected internal override void CreateParameter(List<SqlParameter> parameters, object value, Forbidden forbidden)
{
if (!Identity)
parameters.Add(SqlParameterBuilder.CreateReferenceParameter(Name, false, (int?)value));
}
}
public partial class ValueField
{
protected internal override void CreateParameter(List<SqlParameter> parameters, object value, Forbidden forbidden)
{
parameters.Add(SqlParameterBuilder.CreateParameter(Name, SqlDbType, Nullable, value));
}
}
public static partial class CampoReferenciaExtensions
{
public static int? GetIdForLazy(this IReferenceField cr, object value, Forbidden forbidden)
{
return value == null ? null :
cr.IsLazy ? ((Lazy)value).Map(l => l.UntypedEntityOrNull == null ? l.ID :
forbidden.Contains(l.UntypedEntityOrNull) ? (int?)null :
l.RefreshId()) :
((IdentifiableEntity)value).Map(ei => forbidden.Contains(ei) ? (int?)null : ei.Id);
}
public static Type GetTypeForLazy(this IReferenceField cr, object value, Forbidden forbidden)
{
return value == null ? null :
cr.IsLazy ? ((Lazy)value).Map(l => l.UntypedEntityOrNull == null ? l.RuntimeType :
forbidden.Contains(l.UntypedEntityOrNull) ? null :
l.RuntimeType) :
((IdentifiableEntity)value).Map(ei => forbidden.Contains(ei) ? null : ei.GetType());
}
}
public partial class ReferenceField
{
protected internal override void CreateParameter(List<SqlParameter> parameters, object value, Forbidden forbidden)
{
parameters.Add(SqlParameterBuilder.CreateReferenceParameter(Name, Nullable, this.GetIdForLazy(value, forbidden)));
}
}
public partial class EnumField
{
protected internal override void CreateParameter(List<SqlParameter> parameters, object value, Forbidden forbidden)
{
base.CreateParameter(parameters, EnumProxy.FromEnum((Enum)value), forbidden);
}
}
public partial class CollectionField
{
}
public partial class EmbeddedField
{
protected internal override void CreateParameter(List<SqlParameter> parameters, object value, Forbidden forbidden)
{
if (value != null)
{
EmbeddedEntity ec = (EmbeddedEntity)value;
ec.Modified = false;
EmbeddedFields.ForEach(c => c.Value.CreateParameter(parameters, c.Value.Getter(value), forbidden));
}
}
}
public partial class ImplementedByField
{
protected internal override void CreateParameter(List<SqlParameter> parameters, object value, Forbidden forbidden)
{
Type valType = value == null ? null :
value is Lazy ? ((Lazy)value).RuntimeType :
value.GetType();
var param = ImplementationColumns.Select(p =>
SqlParameterBuilder.CreateReferenceParameter(p.Value.Name, true,
p.Key != valType ? null : this.GetIdForLazy(value, forbidden))).ToList();
if (value != null && !param.Any(p => p.Value != null))
throw new InvalidOperationException(Resources.Type0IsNotAMappedType1.Formato(value.GetType(), ImplementationColumns.Keys.ToString(k => k.Name, ", ")));
parameters.AddRange(param);
}
}
public partial class ImplementationColumn
{
}
public partial class ImplementedByAllField
{
protected internal override void CreateParameter(List<SqlParameter> parameters, object value, Forbidden forbidden)
{
if (value != null)
{
parameters.Add(SqlParameterBuilder.CreateReferenceParameter(Column.Name, Column.Nullable, this.GetIdForLazy(value, forbidden)));
parameters.Add(SqlParameterBuilder.CreateReferenceParameter(ColumnTypes.Name,ColumnTypes.Nullable, this.GetTypeForLazy(value, forbidden).TryCS(t => Schema.Current.IDsForType[t])));
}
}
}
}