using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; using System.Data.Entity; namespace Tango.BL.Builders { public abstract class EntityBuilderBase : IEntityBuilder where T : ObservableEntity where TBuilder : EntityBuilderBase { private List> _steps; private bool _entity_set; private bool abort_build; private List, IQueryable>>> _querySteps; protected T Entity { get; set; } protected String EntityGuid { get; set; } protected ObservablesContext Context { get; set; } public EntityBuilderBase(ObservablesContext context) { _steps = new List>(); _querySteps = new List, IQueryable>>>(); Context = context; } public virtual TBuilder Set(Expression> condition) { ThrowIfEntitySet(); AddStep(0, () => { abort_build = false; IQueryable query = Context.Set().Where(condition); query = OnSetQuery(query); foreach (var queryStep in _querySteps.ToList().DistinctBy(x => x.Key).OrderBy(x => x.Key)) { query = queryStep.Value(query); } Entity = query.FirstOrDefault(); abort_build = Entity == null; }); _entity_set = true; return this as TBuilder; } public virtual TBuilder SetFirst() { ThrowIfEntitySet(); AddStep(0, () => { abort_build = false; IQueryable query = Context.Set(); query = OnSetQuery(query); foreach (var queryStep in _querySteps.ToList().DistinctBy(x => x.Key).OrderBy(x => x.Key)) { query = queryStep.Value(query); } Entity = query.FirstOrDefault(); abort_build = Entity == null; }); _entity_set = true; return this as TBuilder; } public virtual TBuilder Set(T entity) { Entity = entity; EntityGuid = entity?.Guid; return Set(entity.Guid); } public TBuilder Set(string guid) { EntityGuid = guid; return Set(x => x.Guid == guid); } private void ThrowIfEntitySet() { if (_entity_set) throw new InvalidOperationException("Could not set entity. Entity was already set."); } protected virtual IQueryable OnSetQuery(IQueryable query) { return query; } protected TBuilder AddStep(int index, Action action) { _steps.Add(new KeyValuePair(index, action)); return this as TBuilder; } protected TBuilder AddQueryStep(int index, Func, IQueryable> func) { _querySteps.Add(new KeyValuePair, IQueryable>>(index, func)); return this as TBuilder; } protected void CommitSteps() { foreach (var step in _steps.ToList().DistinctBy(x => x.Key).OrderBy(x => x.Key)) { if (!abort_build) { step.Value(); _steps.Remove(step); } } } public virtual T Build() { if (!_entity_set) { throw new InvalidOperationException("Could not build entity. Entity was not set."); } CommitSteps(); return Entity; } public Task BuildAsync() { return Task.Factory.StartNew(() => { return Build(); }); } } }