Skip to content

Commit 3d115f0

Browse files
Update source
Update source
1 parent 1ca8fec commit 3d115f0

File tree

8 files changed

+210
-87
lines changed

8 files changed

+210
-87
lines changed

src/shared/Z.EF.Plus.BatchDelete.Shared/BatchDelete.cs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ public int Execute<T>(IQueryable<T> query) where T : class
203203
return 0;
204204
}
205205

206-
// GET model and info
206+
// GET model and info
207207
#if EF5 || EF6
208208
var dbContext = query.GetDbContext();
209209

@@ -324,17 +324,19 @@ public int Execute<T>(IQueryable<T> query) where T : class
324324
}
325325
}
326326
#elif EFCORE
327-
if (BatchDeleteManager.InMemoryDbContextFactory != null && query.IsInMemoryQueryContext())
328-
{
329-
var context = BatchDeleteManager.InMemoryDbContextFactory();
327+
if (query.IsInMemoryQueryContext())
328+
{
329+
var queryContext = query.GetInMemoryContext();
330330

331-
var list = query.ToList();
332-
context.RemoveRange(list);
333-
context.SaveChanges();
334-
return list.Count;
335-
}
331+
var context = BatchDeleteManager.CreateFactoryContext(queryContext);
336332

337-
var dbContext = query.GetDbContext();
333+
var list = query.ToList();
334+
context.RemoveRange(list);
335+
context.SaveChanges();
336+
return list.Count;
337+
}
338+
339+
var dbContext = query.GetDbContext();
338340
var entity = dbContext.Model.FindEntityType(typeof(T));
339341
var keys = entity.GetKeys().ToList()[0].Properties;
340342

@@ -660,6 +662,7 @@ public DbCommand CreateCommand(IQueryable query, IEntityType entity)
660662
}
661663
else if (isPostgreSQL)
662664
{
665+
List<Tuple<string, string>> propertyAndColumnName = new List<Tuple<string, string>>();
663666
var sqlServer = (IRelationalEntityTypeAnnotations)dynamicProviderEntityType.Invoke(null, new[] { entity });
664667

665668
// GET mapping
@@ -673,10 +676,11 @@ public DbCommand CreateCommand(IQueryable query, IEntityType entity)
673676
var mappingProperty = dynamicProviderProperty.Invoke(null, new[] { propertyKey });
674677

675678
var columnNameProperty = mappingProperty.GetType().GetProperty("ColumnName", BindingFlags.Public | BindingFlags.Instance);
676-
columnKeys.Add((string)columnNameProperty.GetValue(mappingProperty));
679+
//columnKeys.Add((string)columnNameProperty.GetValue(mappingProperty));
680+
propertyAndColumnName.Add(new Tuple<string, string>(propertyKey.Name, (string)columnNameProperty.GetValue(mappingProperty)));
677681
}
678682

679-
primaryKeys = string.Join(Environment.NewLine + "AND ", columnKeys.Select(x => string.Concat("A.\"", x, "\" = B.\"", x, "\"")));
683+
primaryKeys = string.Join(Environment.NewLine + "AND ", propertyAndColumnName.Select(x => string.Concat("A.\"", x.Item2, "\" = B.\"", x.Item1, "\"")));
680684
}
681685
else if (isMySqlPomelo)
682686
{

src/shared/Z.EF.Plus.BatchDelete.Shared/BatchDeleteManager.cs

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,83 @@
66
// Copyright © ZZZ Projects Inc. 2014 - 2016. All rights reserved.
77

88
using System;
9+
using System.Collections.Generic;
10+
using System.Reflection;
911
#if EFCORE
1012
using Microsoft.EntityFrameworkCore;
1113
#endif
1214

1315
namespace Z.EntityFramework.Plus
1416
{
15-
/// <summary>Manage EF+ Batch Delete Configuration.</summary>
16-
public class BatchDeleteManager
17-
{
18-
/// <summary>Gets or sets the batch delete builder to change default configuration.</summary>
19-
/// <value>The batch delete builder to change default configuration.</value>
20-
public static Action<BatchDelete> BatchDeleteBuilder { get; set; }
17+
/// <summary>Manage EF+ Batch Delete Configuration.</summary>
18+
public class BatchDeleteManager
19+
{
20+
/// <summary>Gets or sets the batch delete builder to change default configuration.</summary>
21+
/// <value>The batch delete builder to change default configuration.</value>
22+
public static Action<BatchDelete> BatchDeleteBuilder { get; set; }
2123

2224
#if EFCORE
2325

24-
/// <summary>Gets or sets the factory to create an InMemory DbContext.</summary>
25-
/// <value>The factory to create an InMemory DbContext.</value>
26-
public static Func<DbContext> InMemoryDbContextFactory { get; set; }
26+
/// <summary>Gets or sets the factory to create an InMemory DbContext.</summary>
27+
/// <value>The factory to create an InMemory DbContext.</value>
28+
public static Func<DbContext> InMemoryDbContextFactory { get; set; }
29+
30+
internal static DbContext CreateFactoryContext(DbContext context )
31+
{
32+
if (InMemoryDbContextFactory != null)
33+
{
34+
var newContext = InMemoryDbContextFactory();
35+
36+
if (newContext != null)
37+
{
38+
if (newContext.GetType() == context.GetType())
39+
{
40+
var optionsField = typeof(DbContext).GetField("_options",
41+
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
42+
var originalOptions = optionsField.GetValue(context);
43+
optionsField.SetValue(newContext, originalOptions);
44+
}
45+
46+
EnsureContextSimilar(context, newContext);
47+
return newContext;
48+
}
49+
}
50+
51+
var type = context.GetType();
52+
var emtptyConstructor = type.GetConstructor(new Type[0]);
53+
54+
if (emtptyConstructor != null)
55+
{
56+
var newContext = (DbContext) emtptyConstructor.Invoke(new object[0]);
57+
58+
var optionsField = typeof(DbContext).GetField("_options",
59+
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
60+
var originalOptions = optionsField.GetValue(context);
61+
optionsField.SetValue(newContext, originalOptions);
62+
63+
EnsureContextSimilar(context, newContext);
64+
return newContext;
65+
}
66+
67+
throw new Exception(
68+
"A default DbContext context must exist, or a context factory must be provided (BatchDeleteManager.BatchDeleteBuilder). This setting is required for some additional features. Read more: http://entityframework-extensions.net/context-factory");
69+
}
70+
71+
internal static void EnsureContextSimilar(DbContext originalContext, DbContext newContext)
72+
{
73+
if (originalContext.IsInMemory() && !newContext.IsInMemory())
74+
{
75+
throw new Exception(
76+
"Oops! The original context was an “InMemory” provider. Make sure that the method BatchDeleteManager.BatchDeleteBuilder returns an InMemory provider.");
77+
}
78+
}
79+
2780
#else
2881
/// <summary>
2982
/// Gets or sets a value indicating whether this object is in memory query.
3083
/// </summary>
3184
/// <value>True if this object is in memory query, false if not.</value>
3285
public static bool IsInMemoryQuery { get; set; }
3386
#endif
34-
}
35-
}
87+
}
88+
}

src/shared/Z.EF.Plus.BatchUpdate.Shared/BatchUpdate.cs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,10 @@ public BatchUpdate()
192192
/// <value>True if use table lock, false if not.</value>
193193
public bool UseTableLock { get; set; }
194194

195+
/// <summary>Gets or sets a value indicating whether this object use row lock.</summary>
196+
/// <value>True if use row lock, false if not.</value>
197+
public bool UseRowLock { get; set; }
198+
195199
/// <summary>Executes the batch delete operation.</summary>
196200
/// <typeparam name="T">The type of elements of the query.</typeparam>
197201
/// <param name="query">The query used to execute the batch operation.</param>
@@ -329,11 +333,14 @@ public int Execute<T>(IQueryable<T> query, Expression<Func<T, T>> updateFactory)
329333
}
330334
}
331335
#elif EFCORE
332-
if (BatchUpdateManager.InMemoryDbContextFactory != null && query.IsInMemoryQueryContext())
333-
{
334-
var context = BatchUpdateManager.InMemoryDbContextFactory();
336+
if (query.IsInMemoryQueryContext())
337+
{
338+
var queryContext = query.GetInMemoryContext();
335339

336-
var list = query.ToList();
340+
var context = BatchUpdateManager.CreateFactoryContext(queryContext);
341+
342+
343+
var list = query.ToList();
337344
var compiled = updateFactory.Compile();
338345
var memberBindings = ((MemberInitExpression)updateFactory.Body).Bindings;
339346
var accessors = memberBindings
@@ -350,7 +357,10 @@ public int Execute<T>(IQueryable<T> query, Expression<Func<T, T>> updateFactory)
350357
var value = accessor.GetValue(newItem);
351358
accessor.SetValue(item, value);
352359
}
353-
}
360+
361+
var entityAttached = context.Attach(item);
362+
entityAttached.State = EntityState.Modified;
363+
}
354364

355365
context.SaveChanges();
356366
return list.Count;
@@ -968,10 +978,10 @@ public DbCommand CreateCommand(IQueryable query, IEntityType entity, List<Tuple<
968978
.Replace("{PrimaryKeys}", primaryKeys)
969979
.Replace("{setColumn}", setColumns)
970980
.Replace("{SetValue}", setValues)
971-
.Replace("{Hint}", UseTableLock ? "WITH ( TABLOCK )" : "");
981+
.Replace("{Hint}", UseTableLock ? "WITH ( TABLOCK )" : UseRowLock ? "WITH ( ROWLOCK )" : "");
972982

973-
// CREATE command
974-
var command = query.GetDbContext().CreateStoreCommand();
983+
// CREATE command
984+
var command = query.GetDbContext().CreateStoreCommand();
975985
command.CommandText = commandTextTemplate;
976986

977987
#if EFCORE

src/shared/Z.EF.Plus.BatchUpdate.Shared/BatchUpdateManager.cs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// Copyright © ZZZ Projects Inc. 2014 - 2016. All rights reserved.
77

88
using System;
9-
9+
using System.Reflection;
1010
#if EFCORE
1111
using Microsoft.EntityFrameworkCore;
1212
#endif
@@ -25,6 +25,57 @@ public class BatchUpdateManager
2525
/// <summary>Gets or sets the factory to create an InMemory DbContext.</summary>
2626
/// <value>The factory to create an InMemory DbContext.</value>
2727
public static Func<DbContext> InMemoryDbContextFactory { get; set; }
28+
29+
internal static DbContext CreateFactoryContext(DbContext context)
30+
{
31+
if (InMemoryDbContextFactory != null)
32+
{
33+
var newContext = InMemoryDbContextFactory();
34+
35+
if (newContext != null)
36+
{
37+
if (newContext.GetType() == context.GetType())
38+
{
39+
var optionsField = typeof(DbContext).GetField("_options",
40+
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
41+
var originalOptions = optionsField.GetValue(context);
42+
optionsField.SetValue(newContext, originalOptions);
43+
}
44+
45+
EnsureContextSimilar(context, newContext);
46+
return newContext;
47+
}
48+
}
49+
50+
var type = context.GetType();
51+
var emtptyConstructor = type.GetConstructor(new Type[0]);
52+
53+
if (emtptyConstructor != null)
54+
{
55+
var newContext = (DbContext)emtptyConstructor.Invoke(new object[0]);
56+
57+
var optionsField = typeof(DbContext).GetField("_options",
58+
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
59+
var originalOptions = optionsField.GetValue(context);
60+
optionsField.SetValue(newContext, originalOptions);
61+
62+
EnsureContextSimilar(context, newContext);
63+
return newContext;
64+
}
65+
66+
throw new Exception(
67+
"A default DbContext context must exist, or a context factory must be provided (BatchDeleteManager.BatchDeleteBuilder). This setting is required for some additional features. Read more: http://entityframework-extensions.net/context-factory");
68+
}
69+
70+
internal static void EnsureContextSimilar(DbContext originalContext, DbContext newContext)
71+
{
72+
if (originalContext.IsInMemory() && !newContext.IsInMemory())
73+
{
74+
throw new Exception(
75+
"Oops! The original context was an “InMemory” provider. Make sure that the method BatchDeleteManager.BatchDeleteBuilder returns an InMemory provider.");
76+
}
77+
}
78+
2879
#else
2980
/// <summary>
3081
/// Gets or sets a value indicating whether this object is in memory query.
@@ -33,4 +84,4 @@ public class BatchUpdateManager
3384
public static bool IsInMemoryQuery { get; set; }
3485
#endif
3586
}
36-
}
87+
}

src/shared/Z.EF.Plus._Core.Shared/EF/DbParameter/DbParameter.CopyFrom.cs

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -123,25 +123,8 @@ public static void CopyFrom(this DbParameter @this, ObjectParameter from, string
123123
#if EFCORE
124124
public static void CopyFrom(this DbParameter @this, IRelationalParameter from, object value)
125125
{
126-
@this.ParameterName = from.InvariantName;
127-
128-
if (from is TypeMappedRelationalParameter)
129-
{
130-
var relationalTypeMappingProperty = typeof(TypeMappedRelationalParameter).GetProperty("RelationalTypeMapping", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
131-
132-
if (relationalTypeMappingProperty != null)
133-
{
134-
var relationalTypeMapping = (RelationalTypeMapping)relationalTypeMappingProperty.GetValue(from);
135-
136-
if (relationalTypeMapping.DbType.HasValue)
137-
{
138-
@this.DbType = relationalTypeMapping.DbType.Value;
139-
}
140-
}
141-
}
142-
143-
@this.Value = value ?? DBNull.Value;
144-
}
126+
CopyFrom(@this, from, value, from.InvariantName);
127+
}
145128

146129
public static void CopyFrom(this DbParameter @this, IRelationalParameter from, object value, string newParameterName)
147130
{
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#if EFCORE
2+
using System.Linq;
3+
using Microsoft.EntityFrameworkCore;
4+
5+
namespace Z.EntityFramework.Plus
6+
{
7+
public static partial class DbContextExtensions
8+
{
9+
public static bool IsInMemory(this DbContext @this)
10+
{
11+
return @this.Database.ProviderName == "Microsoft.EntityFrameworkCore.InMemory";
12+
}
13+
}
14+
}
15+
#endif

0 commit comments

Comments
 (0)