Mercurial > pub > bltoolkit
view Source/ServiceModel/DataService.cs @ 9:1e85f66cf767 default tip
update bltoolkit
author | nickolay |
---|---|
date | Thu, 05 Apr 2018 20:53:26 +0300 |
parents | f990fcb411a9 |
children |
line wrap: on
line source
using System; using System.Collections.Generic; using System.Data.Services.Providers; using System.Linq; using System.Linq.Expressions; namespace BLToolkit.ServiceModel { using Data.Linq; using Data.Sql; using Mapping; public class DataService<T> : System.Data.Services.DataService<T>, IServiceProvider where T : IDataContext { #region Init public DataService() { if (_defaultMetadata == null) _defaultMetadata = Tuple.Create(default(T), new MetadataInfo(Map.DefaultSchema)); _metadata = new MetadataProvider(_defaultMetadata.Item2); _query = new QueryProvider (_defaultMetadata.Item2); _update = new UpdateProvider (_defaultMetadata.Item2, _metadata, _query); } static Tuple<T,MetadataInfo> _defaultMetadata; public DataService(MappingSchema mappingSchema) { lock (_cache) { Tuple<T,MetadataInfo> data; if (!_cache.TryGetValue(mappingSchema, out data)) data = Tuple.Create(default(T), new MetadataInfo(mappingSchema)); _metadata = new MetadataProvider(data.Item2); _query = new QueryProvider (data.Item2); _update = new UpdateProvider (data.Item2, _metadata, _query); } } readonly static Dictionary<MappingSchema,Tuple<T,MetadataInfo>> _cache = new Dictionary<MappingSchema,Tuple<T,MetadataInfo>>(); readonly MetadataProvider _metadata; readonly QueryProvider _query; readonly UpdateProvider _update; #endregion #region Public Members public object GetService(Type serviceType) { if (serviceType == typeof(IDataServiceMetadataProvider)) return _metadata; if (serviceType == typeof(IDataServiceQueryProvider)) return _query; if (serviceType == typeof(IDataServiceUpdateProvider)) return _update; return null; } #endregion #region MetadataInfo class TypeInfo { public ResourceType Type; public SqlTable Table; public ObjectMapper Mapper; } class MetadataInfo { public MetadataInfo(MappingSchema mappingSchema) { _mappingSchema = mappingSchema; LoadMetadata(); } readonly MappingSchema _mappingSchema; readonly public Dictionary<Type,TypeInfo> TypeDic = new Dictionary<Type,TypeInfo>(); readonly public Dictionary<string,ResourceType> Types = new Dictionary<string,ResourceType>(); readonly public Dictionary<string,ResourceSet> Sets = new Dictionary<string,ResourceSet>(); readonly public Dictionary<string,Func<object,IQueryable>> RootGetters = new Dictionary<string,Func<object,IQueryable>>(); void LoadMetadata() { var n = 0; var list = ( from p in typeof(T).GetProperties() let t = p.PropertyType where t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Table<>) let tt = t.GetGenericArguments()[0] let tbl = new SqlTable(_mappingSchema, tt) where tbl.Fields.Values.Any(f => f.IsPrimaryKey) let m = _mappingSchema.GetObjectMapper(tt) select new { p.Name, ID = n++, Type = tt, Table = tbl, Mapper = m } ).ToList(); var baseTypes = new Dictionary<Type,Type>(); foreach (var item in list) foreach (var m in item.Mapper.InheritanceMapping) if (!baseTypes.ContainsKey(m.Type)) baseTypes.Add(m.Type, item.Type); list.Sort((x,y) => { Type baseType; if (baseTypes.TryGetValue(x.Type, out baseType)) if (y.Type == baseType) return 1; if (baseTypes.TryGetValue(y.Type, out baseType)) if (x.Type == baseType) return -1; return x.ID - y.ID; }); foreach (var item in list) { Type baseType; baseTypes.TryGetValue(item.Type, out baseType); var type = GetTypeInfo(item.Type, baseType, item.Table, item.Mapper); var set = new ResourceSet(item.Name, type.Type); set.SetReadOnly(); Sets.Add(set.Name, set); } foreach (var item in list) { foreach (var m in item.Mapper.InheritanceMapping) { if (!TypeDic.ContainsKey(m.Type)) { GetTypeInfo( m.Type, item.Type, new SqlTable(_mappingSchema, item.Type), _mappingSchema.GetObjectMapper(item.Type)); } } } } TypeInfo GetTypeInfo(Type type, Type baseType, SqlTable table, ObjectMapper mapper) { TypeInfo typeInfo; if (!TypeDic.TryGetValue(type, out typeInfo)) { var baseInfo = baseType != null ? TypeDic[baseType] : null; typeInfo = new TypeInfo { Type = new ResourceType( type, ResourceTypeKind.EntityType, baseInfo != null ? baseInfo.Type : null, type.Namespace, type.Name, type.IsAbstract), Table = table, Mapper = mapper, }; foreach (var field in table.Fields.Values) { if (baseType != null && baseInfo.Table.Fields.ContainsKey(field.Name)) continue; var kind = ResourcePropertyKind.Primitive; var ptype = ResourceType.GetPrimitiveResourceType(field.SystemType); if (baseType == null && field.IsPrimaryKey) kind |= ResourcePropertyKind.Key; var p = new ResourceProperty(field.Name, kind, ptype); typeInfo.Type.AddProperty(p); } typeInfo.Type.SetReadOnly(); Types. Add(typeInfo.Type.FullName, typeInfo.Type); TypeDic.Add(type, typeInfo); } return typeInfo; } public object CreateInstance(Type type) { return TypeDic[type].Mapper.CreateInstance(); } } #endregion #region MetadataProvider class MetadataProvider : IDataServiceMetadataProvider { public MetadataProvider(MetadataInfo data) { _data = data; } readonly MetadataInfo _data; public bool TryResolveResourceSet(string name, out ResourceSet resourceSet) { return _data.Sets.TryGetValue(name, out resourceSet); } public ResourceAssociationSet GetResourceAssociationSet(ResourceSet resourceSet, ResourceType resourceType, ResourceProperty resourceProperty) { throw new InvalidOperationException(); } public bool TryResolveResourceType(string name, out ResourceType resourceType) { return _data.Types.TryGetValue(name, out resourceType); } public IEnumerable<ResourceType> GetDerivedTypes(ResourceType resourceType) { return _data.TypeDic[resourceType.InstanceType].Mapper.InheritanceMapping.Select(m => _data.TypeDic[m.Type].Type); } public bool HasDerivedTypes(ResourceType resourceType) { return _data.TypeDic[resourceType.InstanceType].Mapper.InheritanceMapping.Count > 0; } public bool TryResolveServiceOperation(string name, out ServiceOperation serviceOperation) { serviceOperation = null; return false; } public string ContainerNamespace { get { return typeof(T).Namespace; } } public string ContainerName { get { return typeof(T).Name; } } public IEnumerable<ResourceSet> ResourceSets { get { return _data.Sets.Values; } } public IEnumerable<ResourceType> Types { get { return _data.Types.Values; } } public IEnumerable<ServiceOperation> ServiceOperations { get { yield break; } } } #endregion #region QueryProvider class QueryProvider : IDataServiceQueryProvider { public QueryProvider(MetadataInfo data) { _data = data; } readonly MetadataInfo _data; public IQueryable GetQueryRootForResourceSet(ResourceSet resourceSet) { Func<object,IQueryable> func; lock (_data.RootGetters) { if (!_data.RootGetters.TryGetValue(resourceSet.Name, out func)) { var p = Expression.Parameter(typeof(object), "p"); var l = Expression.Lambda<Func<object,IQueryable>>( Expression.PropertyOrField( Expression.Convert(p, typeof(T)), resourceSet.Name), p); func = l.Compile(); _data.RootGetters.Add(resourceSet.Name, func); } } return func(CurrentDataSource); } public ResourceType GetResourceType(object target) { return _data.TypeDic[target.GetType()].Type; } public object GetPropertyValue(object target, ResourceProperty resourceProperty) { throw new InvalidOperationException(); } public object GetOpenPropertyValue(object target, string propertyName) { throw new InvalidOperationException(); } public IEnumerable<KeyValuePair<string,object>> GetOpenPropertyValues(object target) { throw new InvalidOperationException(); } public object InvokeServiceOperation(ServiceOperation serviceOperation, object[] parameters) { throw new InvalidOperationException(); } public object CurrentDataSource { get; set; } public bool IsNullPropagationRequired { get { return true; } } } #endregion #region UpdateProvider abstract class ResourceAction { public object Resource; public class Create : ResourceAction {} public class Delete : ResourceAction {} public class Reset : ResourceAction {} public class Update : ResourceAction { public string Property; public object Value; } } class UpdateProvider : IDataServiceUpdateProvider { #region Init public UpdateProvider(MetadataInfo data, MetadataProvider metadata, QueryProvider query) { _data = data; _metadata = metadata; _query = query; } readonly MetadataInfo _data; readonly MetadataProvider _metadata; readonly QueryProvider _query; readonly List<ResourceAction> _actions = new List<ResourceAction>(); #endregion #region IDataServiceUpdateProvider public void SetConcurrencyValues(object resourceCookie, bool? checkForEquality, IEnumerable<KeyValuePair<string,object>> concurrencyValues) { throw new InvalidOperationException(); } public void AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded) { throw new InvalidOperationException(); } public void ClearChanges() { _actions.Clear(); } public object CreateResource(string containerName, string fullTypeName) { ResourceType type; if (_metadata.TryResolveResourceType(fullTypeName, out type)) { var resource = _data.CreateInstance(type.InstanceType); _actions.Add(new ResourceAction.Create { Resource = resource }); return resource; } throw new Exception(string.Format("Type '{0}' not found", fullTypeName)); } public void DeleteResource(object targetResource) { _actions.Add(new ResourceAction.Delete { Resource = targetResource }); } public object GetResource(IQueryable query, string fullTypeName) { object resource = null; foreach (var item in query) { if (resource != null) throw new LinqException("Resource not uniquely identified"); resource = item; } return resource; } public object GetValue(object targetResource, string propertyName) { var m = _data.TypeDic[targetResource.GetType()].Mapper; return m[propertyName, true].GetValue(targetResource); } public void RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved) { throw new InvalidOperationException(); } public object ResetResource(object resource) { _actions.Add(new ResourceAction.Reset { Resource = resource }); return resource; } public object ResolveResource(object resource) { return resource; } public void SaveChanges() { throw new InvalidOperationException(); } public void SetReference(object targetResource, string propertyName, object propertyValue) { throw new InvalidOperationException(); } public void SetValue(object targetResource, string propertyName, object propertyValue) { var m = _data.TypeDic[targetResource.GetType()].Mapper; m[propertyName, true].SetValue(targetResource, propertyValue); _actions.Add(new ResourceAction.Update { Resource = targetResource, Property = propertyName, Value = propertyValue }); } #endregion } #endregion } }