Mercurial > pub > bltoolkit
diff Source/ServiceModel/RemoteDataContextBase.cs @ 0:f990fcb411a9
Копия текущей версии из github
author | cin |
---|---|
date | Thu, 27 Mar 2014 21:46:09 +0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Source/ServiceModel/RemoteDataContextBase.cs Thu Mar 27 21:46:09 2014 +0400 @@ -0,0 +1,276 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq.Expressions; +using System.Text; + +namespace BLToolkit.ServiceModel +{ + using Data.Linq; + using Data.Sql.SqlProvider; + using Mapping; + + public abstract class RemoteDataContextBase : IDataContext + { + protected abstract ILinqService GetClient(); + protected abstract IDataContext Clone (); + protected abstract string ContextIDPrefix { get; } + + string _contextID; + string IDataContext.ContextID + { + get { return _contextID ?? (_contextID = ContextIDPrefix + SqlProviderType.Name.Replace("SqlProvider", "")); } + } + + private MappingSchema _mappingSchema; + public MappingSchema MappingSchema + { + get + { + if (_mappingSchema == null) + { + var sp = ((IDataContext)this).CreateSqlProvider(); + _mappingSchema = sp is IMappingSchemaProvider ? ((IMappingSchemaProvider)sp).MappingSchema : Map.DefaultSchema; + } + + return _mappingSchema; + } + + set { _mappingSchema = value; } + } + + private Type _sqlProviderType; + public virtual Type SqlProviderType + { + get + { + if (_sqlProviderType == null) + { + var client = GetClient(); + + try + { + var type = client.GetSqlProviderType(); + _sqlProviderType = Type.GetType(type); + } + finally + { + ((IDisposable)client).Dispose(); + } + } + + return _sqlProviderType; + } + + set { _sqlProviderType = value; } + } + + public bool IsMarsEnabled + { + get { return false; } + } + + static readonly Dictionary<Type,Func<ISqlProvider>> _sqlProviders = new Dictionary<Type, Func<ISqlProvider>>(); + + Func<ISqlProvider> _createSqlProvider; + + Func<ISqlProvider> IDataContext.CreateSqlProvider + { + get + { + if (_createSqlProvider == null) + { + var type = SqlProviderType; + + if (!_sqlProviders.TryGetValue(type, out _createSqlProvider)) + lock (_sqlProviderType) + if (!_sqlProviders.TryGetValue(type, out _createSqlProvider)) + _sqlProviders.Add(type, _createSqlProvider = Expression.Lambda<Func<ISqlProvider>>(Expression.New(type)).Compile()); + } + + return _createSqlProvider; + } + } + + List<string> _queryBatch; + int _batchCounter; + + public void BeginBatch() + { + _batchCounter++; + + if (_queryBatch == null) + _queryBatch = new List<string>(); + } + + public void CommitBatch() + { + if (_batchCounter == 0) + throw new InvalidOperationException(); + + _batchCounter--; + + if (_batchCounter == 0) + { + var client = GetClient(); + + try + { + var data = LinqServiceSerializer.Serialize(_queryBatch.ToArray()); + client.ExecuteBatch(data); + } + finally + { + ((IDisposable)client).Dispose(); + _queryBatch = null; + } + } + } + + class QueryContext + { + public IQueryContext Query; + public ILinqService Client; + } + + object IDataContext.SetQuery(IQueryContext queryContext) + { + return new QueryContext { Query = queryContext }; + } + + int IDataContext.ExecuteNonQuery(object query) + { + var ctx = (QueryContext)query; + var q = ctx.Query.SqlQuery.ProcessParameters(); + var data = LinqServiceSerializer.Serialize(q, q.IsParameterDependent ? q.Parameters.ToArray() : ctx.Query.GetParameters()); + + if (_batchCounter > 0) + { + _queryBatch.Add(data); + return -1; + } + + ctx.Client = GetClient(); + + return ctx.Client.ExecuteNonQuery(data); + } + + object IDataContext.ExecuteScalar(object query) + { + if (_batchCounter > 0) + throw new LinqException("Incompatible batch operation."); + + var ctx = (QueryContext)query; + + ctx.Client = GetClient(); + + var q = ctx.Query.SqlQuery.ProcessParameters(); + + return ctx.Client.ExecuteScalar( + LinqServiceSerializer.Serialize(q, q.IsParameterDependent ? q.Parameters.ToArray() : ctx.Query.GetParameters())); + } + + IDataReader IDataContext.ExecuteReader(object query) + { + if (_batchCounter > 0) + throw new LinqException("Incompatible batch operation."); + + var ctx = (QueryContext)query; + + ctx.Client = GetClient(); + + var q = ctx.Query.SqlQuery.ProcessParameters(); + var ret = ctx.Client.ExecuteReader( + LinqServiceSerializer.Serialize(q, q.IsParameterDependent ? q.Parameters.ToArray() : ctx.Query.GetParameters())); + var result = LinqServiceSerializer.DeserializeResult(ret); + + return new ServiceModelDataReader(result); + } + + public void ReleaseQuery(object query) + { + var ctx = (QueryContext)query; + + if (ctx.Client != null) + ((IDisposable)ctx.Client).Dispose(); + } + + string IDataContext.GetSqlText(object query) + { + var ctx = (QueryContext)query; + var sqlProvider = ((IDataContext)this).CreateSqlProvider(); + var sb = new StringBuilder(); + + sb + .Append("-- ") + .Append("ServiceModel") + .Append(' ') + .Append(((IDataContext)this).ContextID) + .Append(' ') + .Append(sqlProvider.Name) + .AppendLine(); + + if (ctx.Query.SqlQuery.Parameters != null && ctx.Query.SqlQuery.Parameters.Count > 0) + { + foreach (var p in ctx.Query.SqlQuery.Parameters) + sb + .Append("-- DECLARE ") + .Append(p.Name) + .Append(' ') + .Append(p.Value == null ? p.SystemType.ToString() : p.Value.GetType().Name) + .AppendLine(); + + sb.AppendLine(); + + foreach (var p in ctx.Query.SqlQuery.Parameters) + { + var value = p.Value; + + if (value is string || value is char) + value = "'" + value.ToString().Replace("'", "''") + "'"; + + sb + .Append("-- SET ") + .Append(p.Name) + .Append(" = ") + .Append(value) + .AppendLine(); + } + + sb.AppendLine(); + } + + var cc = sqlProvider.CommandCount(ctx.Query.SqlQuery); + var commands = new string[cc]; + + for (var i = 0; i < cc; i++) + { + sb.Length = 0; + + sqlProvider.BuildSql(i, ctx.Query.SqlQuery, sb, 0, 0, false); + commands[i] = sb.ToString(); + } + + if (!ctx.Query.SqlQuery.IsParameterDependent) + ctx.Query.Context = commands; + + foreach (var command in commands) + sb.AppendLine(command); + + return sb.ToString(); + } + + IDataContext IDataContext.Clone(bool forNestedQuery) + { + return Clone(); + } + + public event EventHandler OnClosing; + + public void Dispose() + { + if (OnClosing != null) + OnClosing(this, EventArgs.Empty); + } + } +}