Skip to content

Commit 0c67544

Browse files
Merge pull request MikaelEliasson#38 from MikaelEliasson/release10
Release 1.0
2 parents 496a1a8 + f3411f6 commit 0c67544

30 files changed

+593
-141
lines changed

EntityFramework.Utilities/EntityFramework.Utilities/App.config

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
<configuration>
33
<configSections>
44
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
5-
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
6-
</configSections>
5+
6+
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --></configSections>
77
<entityFramework>
88
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
99
<parameters>

EntityFramework.Utilities/EntityFramework.Utilities/ColumnMapping.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ namespace EntityFramework.Utilities
66
public class ColumnMapping
77
{
88
public string NameOnObject { get; set; }
9+
public string StaticValue { get; set; }
910
public string NameInDatabase { get; set; }
11+
12+
public string DataType { get; set; }
13+
14+
public bool IsPrimaryKey { get; set; }
1015
}
1116
}

EntityFramework.Utilities/EntityFramework.Utilities/Configuration.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ static Configuration(){
1212
Providers.Add(new SqlQueryProvider());
1313

1414
Log = m => { };
15+
16+
DisableDefaultFallback = true;
1517

1618
}
1719

EntityFramework.Utilities/EntityFramework.Utilities/DatabaseExtensionMethods.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ public static void ForceDelete(this Database db, string name = null)
1919
// if you used master db as Initial Catalog, there is no need to change database
2020
sqlconnection.ChangeDatabase("master");
2121

22-
string rollbackCommand = @"ALTER DATABASE " + name + " SET SINGLE_USER WITH ROLLBACK IMMEDIATE;";
22+
string rollbackCommand = @"ALTER DATABASE [" + name + "] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;";
2323

2424
SqlCommand deletecommand = new SqlCommand(rollbackCommand, sqlconnection);
2525

2626
deletecommand.ExecuteNonQuery();
2727

28-
string deleteCommand = @"DROP DATABASE " + name + ";";
28+
string deleteCommand = @"DROP DATABASE [" + name + "];";
2929

3030
deletecommand = new SqlCommand(deleteCommand, sqlconnection);
3131

EntityFramework.Utilities/EntityFramework.Utilities/EFBatchOperation.cs

Lines changed: 94 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,35 @@ public interface IEFBatchOperationBase<TContext, T> where T : class
2121
/// <param name="items">The items to insert</param>
2222
/// <param name="connection">The DbConnection to use for the insert. Only needed when for example a profiler wraps the connection. Then you need to provide a connection of the type the provider use.</param>
2323
/// <param name="batchSize">The size of each batch. Default depends on the provider. SqlProvider uses 15000 as default</param>
24-
void InsertAll(IEnumerable<T> items, DbConnection connection = null, int? batchSize = null);
24+
void InsertAll<TEntity>(IEnumerable<TEntity> items, DbConnection connection = null, int? batchSize = null) where TEntity : class, T;
2525
IEFBatchOperationFiltered<TContext, T> Where(Expression<Func<T, bool>> predicate);
26+
27+
28+
/// <summary>
29+
/// Bulk update all items if the Provider supports it. Otherwise it will use the default update unless Configuration.DisableDefaultFallback is set to true in which case it would throw an exception.
30+
/// </summary>
31+
/// <typeparam name="TEntity"></typeparam>
32+
/// <param name="items">The items to update</param>
33+
/// <param name="updateSpecification">Define which columns to update</param>
34+
/// <param name="connection">The DbConnection to use for the insert. Only needed when for example a profiler wraps the connection. Then you need to provide a connection of the type the provider use.</param>
35+
/// <param name="batchSize">The size of each batch. Default depends on the provider. SqlProvider uses 15000 as default</param>
36+
void UpdateAll<TEntity>(IEnumerable<TEntity> items, Action<UpdateSpecification<TEntity>> updateSpecification, DbConnection connection = null, int? batchSize = null) where TEntity : class, T;
37+
}
38+
39+
public class UpdateSpecification<T>
40+
{
41+
/// <summary>
42+
/// Set each column you want to update, Columns that belong to the primary key cannot be updated.
43+
/// </summary>
44+
/// <param name="properties"></param>
45+
/// <returns></returns>
46+
public UpdateSpecification<T> ColumnsToUpdate(params Expression<Func<T, object>>[] properties)
47+
{
48+
Properties = properties;
49+
return this;
50+
}
51+
52+
public Expression<Func<T, object>>[] Properties { get; set; }
2653
}
2754

2855
public interface IEFBatchOperationFiltered<TContext, T>
@@ -68,17 +95,17 @@ public static IEFBatchOperationBase<TContext, T> For<TContext, T>(TContext conte
6895
/// <param name="items">The items to insert</param>
6996
/// <param name="connection">The DbConnection to use for the insert. Only needed when for example a profiler wraps the connection. Then you need to provide a connection of the type the provider use.</param>
7097
/// <param name="batchSize">The size of each batch. Default depends on the provider. SqlProvider uses 15000 as default</param>
71-
public void InsertAll(IEnumerable<T> items, DbConnection connection = null, int? batchSize = null)
98+
public void InsertAll<TEntity>(IEnumerable<TEntity> items, DbConnection connection = null, int? batchSize = null) where TEntity : class, T
7299
{
73100
var con = context.Connection as EntityConnection;
74-
if (con == null)
101+
if (con == null && connection == null)
75102
{
76103
Configuration.Log("No provider could be found because the Connection didn't implement System.Data.EntityClient.EntityConnection");
77104
Fallbacks.DefaultInsertAll(context, items);
78105
}
79106

80107
var connectionToUse = connection ?? con.StoreConnection;
81-
108+
var currentType = typeof(TEntity);
82109
var provider = Configuration.Providers.FirstOrDefault(p => p.CanHandle(connectionToUse));
83110
if (provider != null && provider.CanInsert)
84111
{
@@ -87,7 +114,17 @@ public void InsertAll(IEnumerable<T> items, DbConnection connection = null, int?
87114
var typeMapping = mapping.TypeMappings[typeof(T)];
88115
var tableMapping = typeMapping.TableMappings.First();
89116

90-
var properties = tableMapping.PropertyMappings.Select(p => new ColumnMapping { NameInDatabase = p.ColumnName, NameOnObject = p.PropertyName }).ToList();
117+
var properties = tableMapping.PropertyMappings
118+
.Where(p => currentType.IsSubclassOf(p.ForEntityType) || p.ForEntityType == currentType)
119+
.Select(p => new ColumnMapping { NameInDatabase = p.ColumnName, NameOnObject = p.PropertyName }).ToList();
120+
if (tableMapping.TPHConfiguration != null)
121+
{
122+
properties.Add(new ColumnMapping
123+
{
124+
NameInDatabase = tableMapping.TPHConfiguration.ColumnName,
125+
StaticValue = tableMapping.TPHConfiguration.Mappings[typeof(TEntity)]
126+
});
127+
}
91128

92129
provider.InsertItems(items, tableMapping.Schema, tableMapping.TableName, properties, connectionToUse, batchSize);
93130
}
@@ -98,6 +135,55 @@ public void InsertAll(IEnumerable<T> items, DbConnection connection = null, int?
98135
}
99136
}
100137

138+
139+
public void UpdateAll<TEntity>(IEnumerable<TEntity> items, Action<UpdateSpecification<TEntity>> updateSpecification, DbConnection connection = null, int? batchSize = null) where TEntity : class, T
140+
{
141+
var con = context.Connection as EntityConnection;
142+
if (con == null && connection == null)
143+
{
144+
Configuration.Log("No provider could be found because the Connection didn't implement System.Data.EntityClient.EntityConnection");
145+
Fallbacks.DefaultInsertAll(context, items);
146+
}
147+
148+
var connectionToUse = connection ?? con.StoreConnection;
149+
var currentType = typeof(TEntity);
150+
var provider = Configuration.Providers.FirstOrDefault(p => p.CanHandle(connectionToUse));
151+
if (provider != null && provider.CanBulkUpdate)
152+
{
153+
154+
var mapping = EntityFramework.Utilities.EfMappingFactory.GetMappingsForContext(this.dbContext);
155+
var typeMapping = mapping.TypeMappings[typeof(T)];
156+
var tableMapping = typeMapping.TableMappings.First();
157+
158+
var properties = tableMapping.PropertyMappings
159+
.Where(p => currentType.IsSubclassOf(p.ForEntityType) || p.ForEntityType == currentType)
160+
.Select(p => new ColumnMapping {
161+
NameInDatabase = p.ColumnName,
162+
NameOnObject = p.PropertyName,
163+
DataType = p.DataType,
164+
IsPrimaryKey = p.IsPrimaryKey
165+
}).ToList();
166+
167+
if (tableMapping.TPHConfiguration != null)
168+
{
169+
properties.Add(new ColumnMapping
170+
{
171+
NameInDatabase = tableMapping.TPHConfiguration.ColumnName,
172+
StaticValue = tableMapping.TPHConfiguration.Mappings[typeof(TEntity)]
173+
});
174+
}
175+
176+
var spec = new UpdateSpecification<TEntity>();
177+
updateSpecification(spec);
178+
provider.UpdateItems(items, tableMapping.Schema, tableMapping.TableName, properties, connectionToUse, batchSize, spec);
179+
}
180+
else
181+
{
182+
Configuration.Log("Found provider: " + (provider == null ? "[]" : provider.GetType().Name) + " for " + connectionToUse.GetType().Name);
183+
Fallbacks.DefaultInsertAll(context, items);
184+
}
185+
}
186+
101187
public IEFBatchOperationFiltered<TContext, T> Where(Expression<Func<T, bool>> predicate)
102188
{
103189
this.predicate = predicate;
@@ -168,5 +254,8 @@ public int Update<TP>(Expression<Func<T, TP>> prop, Expression<Func<T, TP>> modi
168254
return Fallbacks.DefaultUpdate(context, this.predicate, prop, modifier);
169255
}
170256
}
257+
258+
259+
171260
}
172261
}

EntityFramework.Utilities/EntityFramework.Utilities/EFDataReader.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ public EFDataReader(IEnumerable<T> items, IEnumerable<ColumnMapping> properties)
1919
Properties = properties.Select(p => p.NameOnObject).ToList();
2020
Accessors = properties.Select(p =>
2121
{
22+
if (p.StaticValue != null)
23+
{
24+
Func<T,object> func = x => p.StaticValue;
25+
return func;
26+
}
2227

2328
var parts = p.NameOnObject.Split('.');
2429

EntityFramework.Utilities/EntityFramework.Utilities/EFQueryHelpers.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ private static PropertyInfo SetCollectionModifiersAndGetChildProperty<T, TChild>
140140
childCollectionModifiers.Add(mce);
141141
temp = mce.Arguments[0];
142142
}
143+
//This loop is for VB, See: https://github.com/MikaelEliasson/EntityFramework.Utilities/issues/29
144+
while (temp is UnaryExpression)
145+
{
146+
var ue = temp as UnaryExpression;
147+
temp = ue.Operand;
148+
}
143149
childCollectionModifiers.Reverse(); //We parse from right to left so reverse it
144150
if (!(temp is MemberExpression))
145151
{

EntityFramework.Utilities/EntityFramework.Utilities/EntityFramework.Utilities.csproj

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,11 @@
3232
<ItemGroup>
3333
<Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
3434
<SpecificVersion>False</SpecificVersion>
35-
<HintPath>..\packages\EntityFramework.6.0.2\lib\net40\EntityFramework.dll</HintPath>
35+
<HintPath>..\packages\EntityFramework.6.1.3\lib\net40\EntityFramework.dll</HintPath>
3636
</Reference>
37-
<Reference Include="EntityFramework.SqlServer">
38-
<HintPath>..\packages\EntityFramework.6.0.2\lib\net40\EntityFramework.SqlServer.dll</HintPath>
37+
<Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
38+
<SpecificVersion>False</SpecificVersion>
39+
<HintPath>..\packages\EntityFramework.6.1.3\lib\net40\EntityFramework.SqlServer.dll</HintPath>
3940
</Reference>
4041
<Reference Include="System" />
4142
<Reference Include="System.ComponentModel.DataAnnotations" />

EntityFramework.Utilities/EntityFramework.Utilities/ExpressionHelper.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,19 @@ internal static Expression<Func<T, bool>> CombineExpressions<T, TP>(Expression<F
3030
return final;
3131
}
3232

33+
public static string GetPropertyName<TSource, TProperty>(this Expression<Func<TSource, TProperty>> propertyLambda)
34+
{
35+
Type type = typeof(TSource);
36+
37+
var temp = propertyLambda.Body;
38+
while (temp is UnaryExpression)
39+
{
40+
temp = (temp as UnaryExpression).Operand;
41+
}
42+
MemberExpression member = temp as MemberExpression;
43+
return member.Member.Name;
44+
}
45+
3346
//http://stackoverflow.com/a/2824409/507279
3447
internal static Action<T, TP> PropertyExpressionToSetter<T, TP>(Expression<Func<T, TP>> prop)
3548
{

EntityFramework.Utilities/EntityFramework.Utilities/IQueryProvider.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,18 @@ public interface IQueryProvider
1111
bool CanDelete { get; }
1212
bool CanUpdate { get; }
1313
bool CanInsert { get; }
14+
bool CanBulkUpdate { get; }
1415

1516
string GetDeleteQuery(QueryInformation queryInformation);
1617
string GetUpdateQuery(QueryInformation predicateQueryInfo, QueryInformation modificationQueryInfo);
1718
void InsertItems<T>(IEnumerable<T> items, string schema, string tableName, IList<ColumnMapping> properties, DbConnection storeConnection, int? batchSize);
19+
void UpdateItems<T>(IEnumerable<T> items, string schema, string tableName, IList<ColumnMapping> properties, DbConnection storeConnection, int? batchSize, UpdateSpecification<T> updateSpecification);
1820

1921
bool CanHandle(DbConnection storeConnection);
2022

2123

2224
QueryInformation GetQueryInformation<T>(System.Data.Entity.Core.Objects.ObjectQuery<T> query);
25+
26+
2327
}
2428
}

0 commit comments

Comments
 (0)