5 // Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne
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:
14 // The above copyright notice and this permission notice shall be included in
15 // all copies or substantial portions of the Software.
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
28 using System.Collections;
30 using System.Data.Common;
31 using System.Data.Linq.Mapping;
32 using System.Collections.Generic;
35 using System.Reflection;
38 using System.Data.Linq.Implementation;
39 using System.Data.Linq.Sugar;
40 using System.Data.Linq.Identity;
42 using AttributeMappingSource = System.Data.Linq.Mapping.AttributeMappingSource;
43 using MappingContext = System.Data.Linq.Mapping.MappingContext;
46 using DbLinq.Data.Linq.Implementation;
47 using DbLinq.Data.Linq.Sugar;
48 using DbLinq.Data.Linq.Identity;
50 using AttributeMappingSource = DbLinq.Data.Linq.Mapping.AttributeMappingSource;
51 using MappingContext = DbLinq.Data.Linq.Mapping.MappingContext;
52 using System.Data.Linq;
57 using DbLinq.Data.Linq.Database;
58 using DbLinq.Data.Linq.Database.Implementation;
59 using System.Linq.Expressions;
60 using System.Reflection.Emit;
63 namespace System.Data.Linq
65 namespace DbLinq.Data.Linq
68 public partial class DataContext : IDisposable
70 //private readonly Dictionary<string, ITable> _tableMap = new Dictionary<string, ITable>();
71 private readonly Dictionary<Type, ITable> _tableMap = new Dictionary<Type, ITable>();
73 public MetaModel Mapping { get; private set; }
74 // PC question: at ctor, we get a IDbConnection and the Connection property exposes a DbConnection
76 public DbConnection Connection { get { return DatabaseContext.Connection as DbConnection; } }
78 // all properties below are set public to optionally be injected
79 internal IVendor Vendor { get; set; }
80 internal IQueryBuilder QueryBuilder { get; set; }
81 internal IQueryRunner QueryRunner { get; set; }
82 internal IMemberModificationHandler MemberModificationHandler { get; set; }
83 internal IDatabaseContext DatabaseContext { get; private set; }
86 private readonly EntityTracker entityTracker = new EntityTracker();
88 private IIdentityReaderFactory identityReaderFactory;
89 private readonly IDictionary<Type, IIdentityReader> identityReaders = new Dictionary<Type, IIdentityReader>();
92 /// The default behavior creates one MappingContext.
95 internal virtual MappingContext _MappingContext { get; set; }
98 internal IVendorProvider _VendorProvider { get; set; }
100 public DataContext(IDbConnection connection, MappingSource mapping)
102 Init(new DatabaseContext(connection), mapping, null);
105 public DataContext(IDbConnection connection)
107 Init(new DatabaseContext(connection), null, null);
111 public DataContext(string fileOrServerOrConnection, MappingSource mapping)
113 throw new NotImplementedException();
117 /// Construct DataContext, given a connectionString.
118 /// To determine which DB type to go against, we look for 'DbLinqProvider=xxx' substring.
119 /// If not found, we assume that we are dealing with MS Sql Server.
121 /// Valid values are names of provider DLLs (or any other DLL containing an IVendor implementation)
122 /// DbLinqProvider=Mysql
123 /// DbLinqProvider=Oracle etc.
125 /// <param name="connectionString">specifies file or server connection</param>
127 public DataContext(string connectionString)
129 #region DataContext connectionString ctor
130 if (connectionString == null)
131 throw new ArgumentNullException("connectionString");
133 System.Text.RegularExpressions.Regex reProvider
134 = new System.Text.RegularExpressions.Regex(@"DbLinqProvider=([\w\.]+)");
136 int startPos = connectionString.IndexOf("DbLinqProvider=");
137 string assemblyToLoad;
138 string vendorClassToLoad;
139 if (!reProvider.IsMatch(connectionString))
141 assemblyToLoad = "DbLinq.SqlServer.dll";
142 vendorClassToLoad = "SqlServerVendor";
146 System.Text.RegularExpressions.Match match = reProvider.Match(connectionString);
148 //Pascal says on the forum:
149 //[in MONO] "all vendors are (will be) embedded in the System.Data.Linq assembly"
150 assemblyToLoad = "System.Data.Linq.dll";
151 vendorClassToLoad = match.Groups[1].Value; //eg. "MySql"
153 //plain DbLinq - non MONO:
154 //IVendor classes are in DLLs such as "DbLinq.MySql.dll"
155 assemblyToLoad = match.Groups[1].Value; //eg. assemblyToLoad="DbLinq.MySql.dll"
156 if (assemblyToLoad.Contains("."))
158 //already fully qualified DLL name?
159 throw new ArgumentException("Please provide a short name, such as 'MySql', not '" + assemblyToLoad + "'");
163 //we were given short name, such as MySql
164 vendorClassToLoad = assemblyToLoad + "Vendor"; //eg. MySqlVendor
165 assemblyToLoad = "DbLinq." + assemblyToLoad + ".dll"; //eg. DbLinq.MySql.dll
168 //shorten: "DbLinqProvider=X;Server=Y" -> ";Server=Y"
169 string shortenedConnStr = reProvider.Replace(connectionString, "");
170 connectionString = shortenedConnStr;
177 assy = typeof (DataContext).Assembly; // System.Data.Linq.dll
179 //TODO: check if DLL is already loaded?
180 assy = Assembly.LoadFrom(assemblyToLoad);
185 //TODO: add proper logging here
186 Console.WriteLine("DataContext ctor: Assembly load failed for " + assemblyToLoad + ": " + ex);
190 //find IDbProvider class in this assembly:
191 var ctors = (from mod in assy.GetModules()
192 from cls in mod.GetTypes()
193 where cls.GetInterfaces().Contains(typeof(IVendor))
194 && cls.Name.ToLower() == vendorClassToLoad.ToLower()
195 let ctorInfo = cls.GetConstructor(Type.EmptyTypes)
196 where ctorInfo != null
197 select ctorInfo).ToList();
198 if (ctors.Count == 0)
200 string msg = "Found no IVendor class in assembly " + assemblyToLoad + " having a string ctor";
201 throw new ArgumentException(msg);
203 else if (ctors.Count > 1)
205 string msg = "Found more than one IVendor class in assembly " + assemblyToLoad + " having a string ctor";
206 throw new ArgumentException(msg);
208 ConstructorInfo ctorInfo2 = ctors[0];
210 object ivendorObject;
213 ivendorObject = ctorInfo2.Invoke(new object[]{});
217 //TODO: add proper logging here
218 Console.WriteLine("DataContext ctor: Failed to invoke IVendor ctor " + ctorInfo2.Name + ": " + ex);
221 IVendor ivendor = (IVendor)ivendorObject;
222 IDbConnection dbConnection = ivendor.CreateDbConnection(connectionString);
223 Init(new DatabaseContext(dbConnection), null, ivendor);
227 private void Init(IDatabaseContext databaseContext, MappingSource mappingSource, IVendor vendor)
229 if (databaseContext == null)
230 throw new ArgumentNullException("databaseContext");
232 _VendorProvider = ObjectFactory.Get<IVendorProvider>();
234 Vendor = _VendorProvider.FindVendorByProviderType(typeof(SqlClient.Sql2005Provider));
238 DatabaseContext = databaseContext;
240 MemberModificationHandler = ObjectFactory.Create<IMemberModificationHandler>(); // not a singleton: object is stateful
241 QueryBuilder = ObjectFactory.Get<IQueryBuilder>();
242 QueryRunner = ObjectFactory.Get<IQueryRunner>();
244 //EntityMap = ObjectFactory.Create<IEntityMap>();
245 identityReaderFactory = ObjectFactory.Get<IIdentityReaderFactory>();
247 _MappingContext = new MappingContext();
249 // initialize the mapping information
250 if (mappingSource == null)
251 mappingSource = new AttributeMappingSource();
252 Mapping = mappingSource.GetModel(GetType());
256 /// Checks if the table is allready mapped or maps it if not.
258 /// <param name="tableType">Type of the table.</param>
259 /// <exception cref="InvalidOperationException">Thrown if the table is not mappable.</exception>
260 private void CheckTableMapping(Type tableType)
262 //This will throw an exception if the table is not found
263 if(Mapping.GetTable(tableType) == null)
265 throw new InvalidOperationException("The type '" + tableType.Name + "' is not mapped as a Table.");
270 /// Returns a Table for the type TEntity.
272 /// <exception cref="InvalidOperationException">If the type TEntity is not mappable as a Table.</exception>
273 /// <typeparam name="TEntity">The table type.</typeparam>
274 public Table<TEntity> GetTable<TEntity>() where TEntity : class
276 return (Table<TEntity>)GetTable(typeof(TEntity));
280 /// Returns a Table for the given type.
282 /// <param name="type">The table type.</param>
283 /// <exception cref="InvalidOperationException">If the type is not mappable as a Table.</exception>
284 public ITable GetTable(Type type)
288 ITable tableExisting;
289 if (_tableMap.TryGetValue(type, out tableExisting))
290 return tableExisting;
292 //Check for table mapping
293 CheckTableMapping(type);
295 var tableNew = Activator.CreateInstance(
296 typeof(Table<>).MakeGenericType(type)
297 , BindingFlags.NonPublic | BindingFlags.Instance
299 , new object[] { this }
300 , System.Globalization.CultureInfo.CurrentCulture) as ITable;
302 _tableMap[type] = tableNew;
307 public void SubmitChanges()
309 SubmitChanges(ConflictMode.FailOnFirstConflict);
315 /// <returns></returns>
316 public bool DatabaseExists()
320 return Vendor.Ping(this);
329 /// Commits all pending changes to database
331 /// <param name="failureMode"></param>
332 public virtual void SubmitChanges(ConflictMode failureMode)
334 using (DatabaseContext.OpenConnection()) //ConnMgr will close connection for us
335 using (IDatabaseTransaction transaction = DatabaseContext.Transaction())
337 var queryContext = new QueryContext(this);
338 var entityTracks = entityTracker.EnumerateAll().ToList();
339 foreach (var entityTrack in entityTracks)
341 switch (entityTrack.EntityState)
343 case EntityState.ToInsert:
344 var insertQuery = QueryBuilder.GetInsertQuery(entityTrack.Entity, queryContext);
345 QueryRunner.Insert(entityTrack.Entity, insertQuery);
346 Register(entityTrack.Entity);
348 case EntityState.ToWatch:
349 if (MemberModificationHandler.IsModified(entityTrack.Entity, Mapping))
351 var modifiedMembers = MemberModificationHandler.GetModifiedProperties(entityTrack.Entity, Mapping);
352 var updateQuery = QueryBuilder.GetUpdateQuery(entityTrack.Entity, modifiedMembers, queryContext);
353 QueryRunner.Update(entityTrack.Entity, updateQuery, modifiedMembers);
355 RegisterUpdateAgain(entityTrack.Entity);
358 case EntityState.ToDelete:
359 var deleteQuery = QueryBuilder.GetDeleteQuery(entityTrack.Entity, queryContext);
360 QueryRunner.Delete(entityTrack.Entity, deleteQuery);
362 UnregisterDelete(entityTrack.Entity);
365 throw new ArgumentOutOfRangeException();
368 // TODO: handle conflicts (which can only occur when concurrency mode is implemented)
369 transaction.Commit();
374 /// TODO - allow generated methods to call into stored procedures
377 internal IExecuteResult _ExecuteMethodCall(DataContext context, System.Reflection.MethodInfo method, params object[] sqlParams)
379 using (DatabaseContext.OpenConnection())
381 System.Data.Linq.IExecuteResult result = Vendor.ExecuteMethodCall(context, method, sqlParams);
387 protected IExecuteResult ExecuteMethodCall(object instance, System.Reflection.MethodInfo methodInfo, params object[] parameters)
389 throw new NotImplementedException();
392 #region Identity management
395 internal IIdentityReader _GetIdentityReader(Type t)
397 IIdentityReader identityReader;
398 lock (identityReaders)
400 if (!identityReaders.TryGetValue(t, out identityReader))
402 identityReader = identityReaderFactory.GetReader(t, this);
403 identityReaders[t] = identityReader;
406 return identityReader;
410 internal object _GetRegisteredEntity(object entity)
412 // TODO: check what is faster: by identity or by ref
413 var identityReader = _GetIdentityReader(entity.GetType());
414 var identityKey = identityReader.GetIdentityKey(entity);
415 if (identityKey == null) // if we don't have an entitykey here, it means that the entity has no PK
418 var registeredEntityTrack = entityTracker.FindByIdentity(identityKey);
419 if (registeredEntityTrack != null)
420 return registeredEntityTrack.Entity;
424 //internal object GetRegisteredEntityByKey(IdentityKey identityKey)
426 // return EntityMap[identityKey];
430 /// Registers an entity in a watch state
432 /// <param name="entity"></param>
433 /// <returns></returns>
435 internal object _GetOrRegisterEntity(object entity)
437 var identityReader = _GetIdentityReader(entity.GetType());
438 var identityKey = identityReader.GetIdentityKey(entity);
439 SetEntitySetsQueries(entity);
440 SetEntityRefQueries(entity);
442 // if we have no identity, we can't track it
443 if (identityKey == null)
446 // try to find an already registered entity and return it
447 var registeredEntityTrack = entityTracker.FindByIdentity(identityKey);
448 if (registeredEntityTrack != null)
449 return registeredEntityTrack.Entity;
451 // otherwise, register and return
452 entityTracker.RegisterToWatch(entity, identityKey);
456 readonly IDataMapper DataMapper = ObjectFactory.Get<IDataMapper>();
457 private void SetEntityRefQueries(object entity)
459 Type thisType = entity.GetType();
460 IList<MemberInfo> properties = DataMapper.GetEntityRefAssociations(thisType);
463 foreach (PropertyInfo prop in properties)
465 //example of entityRef:Order.Employee
466 AssociationAttribute associationInfo = prop.GetAttribute<AssociationAttribute>();
467 Type otherTableType = prop.PropertyType;
468 IList<MemberInfo> otherPKs = DataMapper.GetPrimaryKeys(Mapping.GetTable(otherTableType));
470 if (otherPKs.Count > 1)
471 throw new NotSupportedException("Multiple keys object not supported yet.");
473 var otherTable = GetTable(otherTableType);
475 //ie:EmployeeTerritories.EmployeeID
477 var thisForeignKeyProperty = thisType.GetProperty(associationInfo.ThisKey);
478 object thisForeignKeyValue = thisForeignKeyProperty.GetValue(entity, null);
480 IEnumerable query = null;
481 if (thisForeignKeyValue != null)
483 ParameterExpression p = Expression.Parameter(otherTableType, "other");
484 Expression predicate;
485 if (!(thisForeignKeyProperty.PropertyType.IsNullable()))
487 predicate = Expression.Equal(Expression.MakeMemberAccess(p, otherPKs.First()),
488 Expression.Constant(thisForeignKeyValue));
492 var ValueProperty = thisForeignKeyProperty.PropertyType.GetProperty("Value");
493 predicate = Expression.Equal(Expression.MakeMemberAccess(p, otherPKs.First()),
494 Expression.Constant(ValueProperty.GetValue(thisForeignKeyValue, null)));
497 query = GetOtherTableQuery(predicate, p, otherTableType, otherTable) as IEnumerable;
498 //it would be interesting surround the above query with a .Take(1) expression for performance.
502 FieldInfo entityRefField = entity.GetType().GetField(associationInfo.Storage, BindingFlags.NonPublic | BindingFlags.Instance);
503 object entityRefValue = null;
505 entityRefValue = Activator.CreateInstance(entityRefField.FieldType, query);
507 entityRefValue = Activator.CreateInstance(entityRefField.FieldType);
508 entityRefField.SetValue(entity, entityRefValue);
513 /// This method is executed when the entity is being registered. Each EntitySet property has a internal query that can be set using the EntitySet.SetSource method.
514 /// Here we set the query source of each EntitySetProperty
516 /// <param name="entity"></param>
517 private void SetEntitySetsQueries(object entity)
519 IList<MemberInfo> properties = DataMapper.GetEntitySetAssociations(entity.GetType());
521 if (properties.Any()) {
522 IList<MemberInfo> thisPKs = DataMapper.GetPrimaryKeys(Mapping.GetTable(entity.GetType()));
524 if (thisPKs.Count > 1)
525 throw new NotSupportedException("Multiple keys object not supported yet.");
527 object primaryKeyValue = (thisPKs.First() as PropertyInfo).GetValue(entity, null);
530 foreach (PropertyInfo prop in properties)
532 //example of entitySet: Employee.EmployeeTerritories
533 var associationInfo = prop.GetAttribute<AssociationAttribute>();
534 Type otherTableType = prop.PropertyType.GetGenericArguments().First();
536 //other table:EmployeeTerritories
537 var otherTable = GetTable(otherTableType);
538 //other table member:EmployeeTerritories.EmployeeID
539 var otherTableMember = otherTableType.GetProperty(associationInfo.OtherKey);
542 ParameterExpression p = Expression.Parameter(otherTableType, "other");
543 Expression predicate;
544 if (!(otherTableMember.PropertyType.IsNullable()))
546 predicate = Expression.Equal(Expression.MakeMemberAccess(p, otherTableMember),
547 Expression.Constant(primaryKeyValue));
551 var ValueProperty = otherTableMember.PropertyType.GetProperty("Value");
552 predicate = Expression.Equal(Expression.MakeMemberAccess(
553 Expression.MakeMemberAccess(p, otherTableMember),
555 Expression.Constant(primaryKeyValue));
558 var query = GetOtherTableQuery(predicate, p, otherTableType, otherTable);
560 var entitySetValue = prop.GetValue(entity, null);
562 if (entitySetValue == null)
564 entitySetValue = Activator.CreateInstance(prop.PropertyType);
565 prop.SetValue(entity, entitySetValue, null);
568 var setSourceMethod = entitySetValue.GetType().GetMethod("SetSource");
569 setSourceMethod.Invoke(entitySetValue, new[] { query });
570 //employee.EmployeeTerritories.SetSource(Table[EmployeesTerritories].Where(other=>other.employeeID="WARTH"))
575 private object GetOtherTableQuery(Expression predicate, ParameterExpression parameter, Type otherTableType, IQueryable otherTable)
577 //predicate: other.EmployeeID== "WARTH"
578 Expression lambdaPredicate = Expression.Lambda(predicate, parameter);
579 //lambdaPredicate: other=>other.EmployeeID== "WARTH"
581 var whereMethod = typeof(Queryable)
582 .GetMethods().First(m => m.Name == "Where")
583 .MakeGenericMethod(otherTableType);
586 Expression call = Expression.Call(whereMethod, otherTable.Expression, lambdaPredicate);
587 //Table[EmployeesTerritories].Where(other=>other.employeeID="WARTH")
589 return otherTable.Provider.CreateQuery(call);
594 #region Insert/Update/Delete management
597 /// Registers an entity for insert
599 /// <param name="entity"></param>
600 internal void RegisterInsert(object entity)
602 entityTracker.RegisterToInsert(entity);
606 /// Registers an entity for update
607 /// The entity will be updated only if some of its members have changed after the registration
609 /// <param name="entity"></param>
610 internal void RegisterUpdate(object entity)
612 var identityReader = _GetIdentityReader(entity.GetType());
613 var identityKey = identityReader.GetIdentityKey(entity);
614 // if we have no key, we can not watch
615 if (identityKey == null)
618 entityTracker.RegisterToWatch(entity, identityKey);
622 /// Registers or re-registers an entity and clears its state
624 /// <param name="entity"></param>
625 /// <returns></returns>
626 internal object Register(object entity)
628 var registeredEntity = _GetOrRegisterEntity(entity);
629 // the fact of registering again clears the modified state, so we're... clear with that
630 MemberModificationHandler.Register(registeredEntity, Mapping);
631 return registeredEntity;
635 /// Registers an entity for update
636 /// The entity will be updated only if some of its members have changed after the registration
638 /// <param name="entity"></param>
639 /// <param name="entityOriginalState"></param>
640 internal void RegisterUpdate(object entity, object entityOriginalState)
642 RegisterUpdate(entity);
643 MemberModificationHandler.Register(entity, entityOriginalState, Mapping);
647 /// Clears the current state, and marks the object as clean
649 /// <param name="entity"></param>
650 internal void RegisterUpdateAgain(object entity)
652 MemberModificationHandler.ClearModified(entity, Mapping);
656 /// Registers an entity for delete
658 /// <param name="entity"></param>
659 internal void RegisterDelete(object entity)
661 entityTracker.RegisterToDelete(entity);
665 /// Unregisters entity after deletion
667 /// <param name="entity"></param>
668 internal void UnregisterDelete(object entity)
670 entityTracker.RegisterDeleted(entity);
676 /// Changed object determine
678 /// <returns>Lists of inserted, updated, deleted objects</returns>
679 public ChangeSet GetChangeSet()
681 var inserts = new List<object>();
682 var updates = new List<object>();
683 var deletes = new List<object>();
684 foreach (var entityTrack in entityTracker.EnumerateAll())
686 switch (entityTrack.EntityState)
688 case EntityState.ToInsert:
689 inserts.Add(entityTrack.Entity);
691 case EntityState.ToWatch:
692 if (MemberModificationHandler.IsModified(entityTrack.Entity, Mapping))
693 updates.Add(entityTrack.Entity);
695 case EntityState.ToDelete:
696 deletes.Add(entityTrack.Entity);
699 throw new ArgumentOutOfRangeException();
702 return new ChangeSet(inserts, updates, deletes);
706 /// use ExecuteCommand to call raw SQL
708 public int ExecuteCommand(string command, params object[] parameters)
710 var directQuery = QueryBuilder.GetDirectQuery(command, new QueryContext(this));
711 return QueryRunner.Execute(directQuery, parameters);
715 /// Execute raw SQL query and return object
717 public IEnumerable<TResult> ExecuteQuery<TResult>(string query, params object[] parameters) where TResult : class, new()
719 //GetTable<TResult>();
720 foreach (TResult result in ExecuteQuery(typeof(TResult), query, parameters))
724 public IEnumerable ExecuteQuery(Type elementType, string query, params object[] parameters)
726 var queryContext = new QueryContext(this);
727 var directQuery = QueryBuilder.GetDirectQuery(query, queryContext);
728 return QueryRunner.ExecuteSelect(elementType, directQuery, parameters);
732 /// Gets or sets the load options
735 public DataLoadOptions LoadOptions { get; set; }
737 public DbTransaction Transaction { get; set; }
740 /// Runs the given reader and returns columns.
742 /// <typeparam name="TResult">The type of the result.</typeparam>
743 /// <param name="reader">The reader.</param>
744 /// <returns></returns>
745 public IEnumerable<TResult> Translate<TResult>(DbDataReader reader)
747 foreach (TResult result in Translate(typeof(TResult), reader))
751 public IMultipleResults Translate(DbDataReader reader)
753 throw new NotImplementedException();
756 public IEnumerable Translate(Type elementType, DbDataReader reader)
758 return QueryRunner.EnumerateResult(elementType, reader, this);
761 public void Dispose()
763 //connection closing should not be done here.
764 //read: http://msdn2.microsoft.com/en-us/library/bb292288.aspx
768 protected virtual void Dispose(bool disposing)
770 throw new NotImplementedException();
774 /// Creates a IDbDataAdapter. Used internally by Vendors
776 /// <returns></returns>
777 internal IDbDataAdapter CreateDataAdapter()
779 return DatabaseContext.CreateDataAdapter();
783 /// Sets a TextWriter where generated SQL commands are written
785 public TextWriter Log { get; set; }
788 /// Writes text on Log (if not null)
791 /// <param name="text"></param>
792 internal void WriteLog(string text)
799 /// Write an IDbCommand to Log (if non null)
801 /// <param name="command"></param>
802 internal void WriteLog(IDbCommand command)
806 Log.WriteLine(command.CommandText);
807 foreach (IDbDataParameter parameter in command.Parameters)
810 Log.Write(" Context: {0}", Vendor.VendorName);
811 Log.Write(" Model: {0}", Mapping.GetType().Name);
812 Log.Write(" Build: {0}", Assembly.GetExecutingAssembly().GetName().Version);
818 /// Writes and IDbDataParameter to Log (if non null)
820 /// <param name="parameter"></param>
821 internal void WriteLog(IDbDataParameter parameter)
825 // -- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [2]
826 // -- <name>: <direction> <type> (...) [<value>]
827 Log.WriteLine("-- {0}: {1} {2} (Size = {3}; Prec = {4}; Scale = {5}) [{6}]",
828 parameter.ParameterName, parameter.Direction, parameter.DbType,
829 parameter.Size, parameter.Precision, parameter.Scale, parameter.Value);
835 public bool ObjectTrackingEnabled
837 get { throw new NotImplementedException(); }
838 set { throw new NotImplementedException(); }
842 public int CommandTimeout
844 get { throw new NotImplementedException(); }
845 set { throw new NotImplementedException(); }
849 public bool DeferredLoadingEnabled
851 get { throw new NotImplementedException(); }
852 set { throw new NotImplementedException(); }
856 public ChangeConflictCollection ChangeConflicts
858 get { throw new NotImplementedException(); }
862 public DbCommand GetCommand(IQueryable query)
864 var qp = query.Provider as QueryProvider;
866 throw new InvalidOperationException();
868 IDbCommand dbCommand = qp.GetQuery(null).GetCommand().Command;
869 if (!(dbCommand is DbCommand))
870 throw new InvalidOperationException();
872 return (DbCommand)dbCommand;
876 public void Refresh(RefreshMode mode, IEnumerable entities)
878 throw new NotImplementedException();
882 public void Refresh(RefreshMode mode, params object[] entities)
884 throw new NotImplementedException();
888 public void Refresh(RefreshMode mode, object entity)
890 throw new NotImplementedException();
894 public void DeleteDatabase()
896 throw new NotImplementedException();
900 public void CreateDatabase()
902 throw new NotImplementedException();
906 protected internal IQueryable<TResult> CreateMethodCallQuery<TResult>(object instance, MethodInfo methodInfo, params object[] parameters)
908 throw new NotImplementedException();
912 protected internal void ExecuteDynamicDelete(object entity)
914 throw new NotImplementedException();
918 protected internal void ExecuteDynamicInsert(object entity)
920 throw new NotImplementedException();
924 protected internal void ExecuteDynamicUpdate(object entity)
926 throw new NotImplementedException();