PageRenderTime 15ms CodeModel.GetById 2ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/class/System.Data.Linq/src/DbLinq/Data/Linq/Sugar/Implementation/DataMapper.cs

https://github.com/ekovalenko-softheme/mono
C# | 214 lines | 131 code | 21 blank | 62 comment | 26 complexity | fc9f09bc774d6d3b7ac79a9bf97bdf22 MD5 | raw file
  1#region MIT license
  2// 
  3// MIT license
  4//
  5// Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne
  6// 
  7// Permission is hereby granted, free of charge, to any person obtaining a copy
  8// of this software and associated documentation files (the "Software"), to deal
  9// in the Software without restriction, including without limitation the rights
 10// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11// copies of the Software, and to permit persons to whom the Software is
 12// furnished to do so, subject to the following conditions:
 13// 
 14// The above copyright notice and this permission notice shall be included in
 15// all copies or substantial portions of the Software.
 16// 
 17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 23// THE SOFTWARE.
 24// 
 25#endregion
 26
 27using System;
 28using System.Collections.Generic;
 29using System.Collections.ObjectModel;
 30using System.Data.Linq.Mapping;
 31using System.Linq;
 32using System.Reflection;
 33
 34using DbLinq.Data.Linq.Sugar.Expressions;
 35
 36#if MONO_STRICT
 37using System.Data.Linq;
 38#else
 39using DbLinq.Data.Linq;
 40#endif
 41
 42namespace DbLinq.Data.Linq.Sugar.Implementation
 43{
 44    internal class DataMapper : IDataMapper
 45    {
 46        /// <summary>
 47        /// Returns a table given a type, or null if the type is not mapped
 48        /// </summary>
 49        /// <param name="tableType"></param>
 50        /// <param name="dataContext"></param>
 51        /// <returns></returns>
 52        public virtual string GetTableName(Type tableType, DataContext dataContext)
 53        {
 54            var tableDescription = dataContext.Mapping.GetTable(tableType);
 55            if (tableDescription != null)
 56                return tableDescription.TableName;
 57            return null;
 58        }
 59
 60        public virtual string GetColumnName(TableExpression tableExpression, MemberInfo memberInfo, DataContext dataContext)
 61        {
 62            return GetColumnName(tableExpression.Type, memberInfo, dataContext);
 63        }
 64
 65        public virtual string GetColumnName(Type tableType, MemberInfo memberInfo, DataContext dataContext)
 66        {
 67            var tableDescription = dataContext.Mapping.GetTable(tableType);
 68            var columnDescription = tableDescription.RowType.GetDataMember(memberInfo);
 69            if (columnDescription != null)
 70                return columnDescription.MappedName;
 71            return null;
 72        }
 73
 74        public virtual IList<MemberInfo> GetPrimaryKeys(TableExpression tableExpression, DataContext dataContext)
 75        {
 76            var tableDescription = dataContext.Mapping.GetTable(tableExpression.Type);
 77            if (tableDescription != null)
 78                return GetPrimaryKeys(tableDescription);
 79            return null;
 80        }
 81
 82        public virtual IList<MemberInfo> GetPrimaryKeys(MetaTable tableDescription)
 83        {
 84            return (from column in tableDescription.RowType.IdentityMembers select column.Member).ToList();
 85        }
 86
 87        /// <summary>
 88        /// Lists table mapped columns
 89        /// </summary>
 90        /// <param name="tableDescription"></param>
 91        /// <returns></returns>
 92        public IList<MemberInfo> GetColumns(MetaTable tableDescription)
 93        {
 94            return (from column in tableDescription.RowType.PersistentDataMembers select column.Member).ToList();
 95        }
 96
 97        /// <summary>
 98        /// Returns association definition, if any
 99        /// </summary>
100        /// <param name="thisTableExpression">The table referenced by the assocation (the type holding the member)</param>
101        /// <param name="memberInfo">The memberInfo related to association</param>
102        /// <param name="otherType"></param>
103        /// <param name="otherKey">The keys in the associated table</param>
104        /// <param name="joinType"></param>
105        /// <param name="joinID"></param>
106        /// <param name="dataContext"></param>
107        /// <returns>ThisKey</returns>
108        public virtual IList<MemberInfo> GetAssociation(TableExpression thisTableExpression, MemberInfo memberInfo, Type otherType, out IList<MemberInfo> otherKey, out TableJoinType joinType, out string joinID, DataContext dataContext)
109        {
110            var thisTableDescription = dataContext.Mapping.GetTable(thisTableExpression.Type);
111            var thisAssociation =
112                (from association in thisTableDescription.RowType.Associations
113                 where association.ThisMember.Member == memberInfo
114                 select association).SingleOrDefault();
115            if (thisAssociation != null)
116            {
117                // by default, join is inner
118                joinType = TableJoinType.Inner;
119                joinID = thisAssociation.ThisMember.MappedName;
120                if (string.IsNullOrEmpty(joinID))
121                    throw Error.BadArgument("S0108: Association name is required to ensure join uniqueness");
122
123                var otherTableDescription = dataContext.Mapping.GetTable(otherType);
124                bool thisKeyHasNullables, otherKeyHasNullables;
125                var thisKey = GetAssociationKeys(thisTableDescription, thisAssociation.ThisKey, dataContext,
126                                                 out thisKeyHasNullables);
127                otherKey = GetAssociationKeys(otherTableDescription, thisAssociation.OtherKey, dataContext,
128                                              out otherKeyHasNullables);
129
130                // we just test here the left join (since associations are symmetric,
131                //        we can only find left joins here, and the otherKeyHasNullables is
132                //        always equal to thisKeyHasNullables)
133                if (thisKeyHasNullables)
134                    joinType |= TableJoinType.LeftOuter;
135
136                return thisKey;
137            }
138            otherKey = null;
139            joinType = TableJoinType.Default;
140            joinID = null;
141            return null;
142        }
143
144        /// <summary>
145        /// Enumerates Keys for a given table.
146        /// Keys can be provided as input. If none provided, PKs are taken from table
147        /// </summary>
148        /// <param name="description"></param>
149        /// <param name="keys">Keys to be used, leave empty to use PKs instead</param>
150        /// <param name="dataContext"></param>
151        /// <param name="hasNullableKeys">returned as true if some keys can be null (we then have an outer join)</param>
152        /// <returns></returns>
153        protected virtual IList<MemberInfo> GetAssociationKeys(MetaTable description, ReadOnlyCollection<MetaDataMember> keys,
154                                                               DataContext dataContext, out bool hasNullableKeys)
155        {
156            var sourceKeys = keys;
157            if (sourceKeys.Count == 0)
158                sourceKeys = description.RowType.IdentityMembers;
159
160            hasNullableKeys = false;
161            var members = new List<MemberInfo>();
162            foreach (var sourceKey in sourceKeys)
163            {
164                members.Add(sourceKey.Member);
165                if (sourceKey.CanBeNull)
166                    hasNullableKeys = true;
167            }
168            return members;
169        }
170
171        public IList<MemberInfo> GetEntitySetAssociations(Type type)
172        {
173            // BUG: This is ignoring External Mappings from XmlMappingSource.
174
175            // TODO: Should be cached in a static thread safe cache.
176
177            return type.GetProperties()
178                .Where(p => p.PropertyType.IsGenericType 
179                    && (p.PropertyType.GetGenericTypeDefinition() == typeof(System.Data.Linq.EntitySet<>) 
180#if !MONO_STRICT
181                    || p.PropertyType.GetGenericTypeDefinition() == typeof(DbLinq.Data.Linq.EntitySet<>)
182#endif
183                    )
184                    && p.IsDefined(typeof(AssociationAttribute), true))
185                .Cast<MemberInfo>().ToList();
186        }
187
188        public IList<MemberInfo> GetEntityRefAssociations(Type type)
189        {
190            // BUG: This is ignoring External Mappings from XmlMappingSource.
191
192            // TODO: Should be cached in a static thread safe cache.
193
194            List<MemberInfo> associations = new List<MemberInfo>();
195            foreach (var p in type.GetProperties())
196            {
197                AssociationAttribute associationAttribute = p.GetCustomAttributes(typeof(AssociationAttribute), true).FirstOrDefault() as AssociationAttribute;
198                if (associationAttribute != null)
199                {
200                    FieldInfo field = type.GetField(associationAttribute.Storage, BindingFlags.NonPublic | BindingFlags.Instance);
201                    if (field != null && field.FieldType.IsGenericType &&
202#if MONO_STRICT
203                        field.FieldType.GetGenericTypeDefinition() == typeof(System.Data.Linq.EntityRef<>)
204#else
205                        field.FieldType.GetGenericTypeDefinition() == typeof(DbLinq.Data.Linq.EntityRef<>)
206#endif
207                        )
208                        associations.Add(p);
209                }
210            }
211            return associations;
212        }
213    }
214}