Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
D
Dapper
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
tsai
Dapper
Commits
b68362f5
Commit
b68362f5
authored
May 26, 2011
by
Sam Saffron
Browse files
Options
Browse Files
Download
Plain Diff
Merge in changes
parents
c394845d
11f393d5
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
106 additions
and
96 deletions
+106
-96
Dapper.Contrib.Tests.csproj
Dapper.Contrib.Tests/Dapper.Contrib.Tests.csproj
+0
-3
Program.cs
Dapper.Contrib.Tests/Program.cs
+2
-5
Tests.cs
Dapper.Contrib.Tests/Tests.cs
+22
-5
ProxyGenerator.cs
Dapper.Contrib/Extensions/ProxyGenerator.cs
+33
-61
SqlMapperExtensions.cs
Dapper.Contrib/Extensions/SqlMapperExtensions.cs
+48
-21
TypeExtension.cs
Dapper.Contrib/Extensions/TypeExtension.cs
+1
-1
No files found.
Dapper.Contrib.Tests/Dapper.Contrib.Tests.csproj
View file @
b68362f5
...
...
@@ -42,9 +42,6 @@
<WarningLevel>
4
</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference
Include=
"EntityFramework"
>
<HintPath>
Dependencies\EntityFramework.dll
</HintPath>
</Reference>
<Reference
Include=
"System"
/>
<Reference
Include=
"System.ComponentModel.DataAnnotations"
/>
<Reference
Include=
"System.Core"
/>
...
...
Dapper.Contrib.Tests/Program.cs
View file @
b68362f5
...
...
@@ -30,11 +30,8 @@ private static void Setup()
using
(
var
connection
=
new
SqlCeConnection
(
connectionString
))
{
connection
.
Open
();
var
sql
=
@"
create table Users (Id int IDENTITY(1,1) not null, Name nvarchar(100) not null, Age int not null)
"
;
connection
.
Execute
(
sql
);
connection
.
Execute
(
@" create table Users (Id int IDENTITY(1,1) not null, Name nvarchar(100) not null, Age int not null) "
);
connection
.
Execute
(
@" create table Automobiles (Id int IDENTITY(1,1) not null, Name nvarchar(100) not null) "
);
}
Console
.
WriteLine
(
"Created database"
);
}
...
...
Dapper.Contrib.Tests/Tests.cs
View file @
b68362f5
using
System
;
using
System.ComponentModel.DataAnnotations
;
using
System.ComponentModel.DataAnnotations
;
using
System.Data
;
using
System.Data.SqlServerCe
;
using
System.Diagnostics
;
using
System.IO
;
using
System.Linq
;
using
System.Reflection
;
using
Dapper.Contrib.Extensions
;
namespace
Dapper.Contrib.Tests
{
public
interface
IUser
...
...
@@ -26,6 +24,13 @@ public class User : IUser
public
int
Age
{
get
;
set
;
}
}
[
Table
(
"Automobiles"
)]
public
class
Car
{
public
int
Id
{
get
;
set
;
}
public
string
Name
{
get
;
set
;
}
}
public
class
Tests
{
private
IDbConnection
GetOpenConnection
()
...
...
@@ -38,7 +43,19 @@ private IDbConnection GetOpenConnection()
return
connection
;
}
public
void
TableName
()
{
using
(
var
connection
=
GetOpenConnection
())
{
// tests against "Automobiles" table (Table attribute)
connection
.
Insert
(
new
Car
{
Name
=
"Volvo"
});
connection
.
Get
<
Car
>(
1
).
Name
.
IsEqualTo
(
"Volvo"
);
connection
.
Update
(
new
Car
()
{
Id
=
1
,
Name
=
"Saab"
}).
IsEqualTo
(
true
);
connection
.
Get
<
Car
>(
1
).
Name
.
IsEqualTo
(
"Saab"
);
connection
.
Delete
(
new
Car
()
{
Id
=
1
}).
IsEqualTo
(
true
);
connection
.
Get
<
Car
>(
1
).
IsNull
();
}
}
public
void
TestSimpleGet
()
{
...
...
Dapper.Contrib/Extensions/ProxyGenerator.cs
View file @
b68362f5
...
...
@@ -76,55 +76,39 @@ public static T GetInterfaceProxy<T>()
private
static
MethodInfo
CreateIsDirtyProperty
(
TypeBuilder
typeBuilder
)
{
Type
propType
=
typeof
(
bool
);
FieldBuilder
field
=
typeBuilder
.
DefineField
(
"_"
+
"IsDirty"
,
propType
,
FieldAttributes
.
Private
);
// Generate a public property
PropertyBuilder
property
=
typeBuilder
.
DefineProperty
(
"IsDirty"
,
var
propType
=
typeof
(
bool
);
var
field
=
typeBuilder
.
DefineField
(
"_"
+
"IsDirty"
,
propType
,
FieldAttributes
.
Private
);
var
property
=
typeBuilder
.
DefineProperty
(
"IsDirty"
,
PropertyAttributes
.
None
,
propType
,
new
Type
[]
{
propType
});
// The property set and property get methods require a special set of attributes:
const
MethodAttributes
getSetAttr
=
MethodAttributes
.
Public
|
MethodAttributes
.
NewSlot
|
MethodAttributes
.
SpecialName
|
MethodAttributes
.
Final
|
MethodAttributes
.
Virtual
|
MethodAttributes
.
HideBySig
;
MethodAttributes
GetSetAttr
=
MethodAttributes
.
Public
|
MethodAttributes
.
NewSlot
|
MethodAttributes
.
SpecialName
|
MethodAttributes
.
Final
|
MethodAttributes
.
Virtual
|
MethodAttributes
.
HideBySig
;
// Define the "get" accessor method for current private field.
MethodBuilder
currGetPropMthdBldr
=
typeBuilder
.
DefineMethod
(
"get_"
+
"IsDirty"
,
GetSetAttr
,
// Define the "get" and "set" accessor methods
var
currGetPropMthdBldr
=
typeBuilder
.
DefineMethod
(
"get_"
+
"IsDirty"
,
getSetAttr
,
propType
,
Type
.
EmptyTypes
);
// Intermediate Language stuff...
ILGenerator
currGetIL
=
currGetPropMthdBldr
.
GetILGenerator
();
var
currGetIL
=
currGetPropMthdBldr
.
GetILGenerator
();
currGetIL
.
Emit
(
OpCodes
.
Ldarg_0
);
currGetIL
.
Emit
(
OpCodes
.
Ldfld
,
field
);
currGetIL
.
Emit
(
OpCodes
.
Ret
);
// Define the "set" accessor method for current private field.
MethodBuilder
currSetPropMthdBldr
=
typeBuilder
.
DefineMethod
(
"set_"
+
"IsDirty"
,
GetSetAttr
,
var
currSetPropMthdBldr
=
typeBuilder
.
DefineMethod
(
"set_"
+
"IsDirty"
,
getSetAttr
,
null
,
new
Type
[]
{
propType
});
// Again some Intermediate Language stuff...
ILGenerator
currSetIL
=
currSetPropMthdBldr
.
GetILGenerator
();
var
currSetIL
=
currSetPropMthdBldr
.
GetILGenerator
();
currSetIL
.
Emit
(
OpCodes
.
Ldarg_0
);
currSetIL
.
Emit
(
OpCodes
.
Ldarg_1
);
currSetIL
.
Emit
(
OpCodes
.
Stfld
,
field
);
currSetIL
.
Emit
(
OpCodes
.
Ret
);
// Last, we must map the two methods created above to our PropertyBuilder to
// their corresponding behaviors, "get" and "set" respectively.
property
.
SetGetMethod
(
currGetPropMthdBldr
);
property
.
SetSetMethod
(
currSetPropMthdBldr
);
MethodInfo
getMethod
=
typeof
(
IProxy
).
GetMethod
(
"get_"
+
"IsDirty"
);
MethodInfo
setMethod
=
typeof
(
IProxy
).
GetMethod
(
"set_"
+
"IsDirty"
);
var
getMethod
=
typeof
(
IProxy
).
GetMethod
(
"get_"
+
"IsDirty"
);
var
setMethod
=
typeof
(
IProxy
).
GetMethod
(
"set_"
+
"IsDirty"
);
typeBuilder
.
DefineMethodOverride
(
currGetPropMthdBldr
,
getMethod
);
typeBuilder
.
DefineMethodOverride
(
currSetPropMthdBldr
,
setMethod
);
...
...
@@ -133,42 +117,34 @@ private static MethodInfo CreateIsDirtyProperty(TypeBuilder typeBuilder)
private
static
void
CreateProperty
<
T
>(
TypeBuilder
typeBuilder
,
string
propertyName
,
Type
propType
,
MethodInfo
setIsDirtyMethod
,
bool
isIdentity
)
{
FieldBuilder
field
=
typeBuilder
.
DefineField
(
"_"
+
propertyName
,
propType
,
FieldAttributes
.
Private
);
// Generate a public property
PropertyBuilder
property
=
typeBuilder
.
DefineProperty
(
propertyName
,
//Define the field and the property
var
field
=
typeBuilder
.
DefineField
(
"_"
+
propertyName
,
propType
,
FieldAttributes
.
Private
);
var
property
=
typeBuilder
.
DefineProperty
(
propertyName
,
PropertyAttributes
.
None
,
propType
,
new
Type
[]
{
propType
});
// The property set and property get methods require a special set of attributes:
MethodAttributes
GetSetAttr
=
MethodAttributes
.
Public
|
MethodAttributes
.
Virtual
|
MethodAttributes
.
HideBySig
;
const
MethodAttributes
getSetAttr
=
MethodAttributes
.
Public
|
MethodAttributes
.
Virtual
|
MethodAttributes
.
HideBySig
;
// Define the "get" accessor method for current private field.
MethodBuilder
currGetPropMthdBldr
=
typeBuilder
.
DefineMethod
(
"get_"
+
propertyName
,
GetSetAttr
,
// Define the "get" and "set" accessor methods
var
currGetPropMthdBldr
=
typeBuilder
.
DefineMethod
(
"get_"
+
propertyName
,
getSetAttr
,
propType
,
Type
.
EmptyTypes
);
// Intermediate Language stuff...
ILGenerator
currGetIL
=
currGetPropMthdBldr
.
GetILGenerator
();
var
currGetIL
=
currGetPropMthdBldr
.
GetILGenerator
();
currGetIL
.
Emit
(
OpCodes
.
Ldarg_0
);
currGetIL
.
Emit
(
OpCodes
.
Ldfld
,
field
);
currGetIL
.
Emit
(
OpCodes
.
Ret
);
// Define the "set" accessor method for current private field.
MethodBuilder
currSetPropMthdBldr
=
typeBuilder
.
DefineMethod
(
"set_"
+
propertyName
,
GetSetAttr
,
var
currSetPropMthdBldr
=
typeBuilder
.
DefineMethod
(
"set_"
+
propertyName
,
getSetAttr
,
null
,
new
Type
[]
{
propType
});
//
Again some Intermediate Language stuff...
ILGenerato
r
currSetIL
=
currSetPropMthdBldr
.
GetILGenerator
();
//
store value in private field and set the isdirty flag
va
r
currSetIL
=
currSetPropMthdBldr
.
GetILGenerator
();
currSetIL
.
Emit
(
OpCodes
.
Ldarg_0
);
currSetIL
.
Emit
(
OpCodes
.
Ldarg_1
);
currSetIL
.
Emit
(
OpCodes
.
Stfld
,
field
);
...
...
@@ -177,23 +153,19 @@ private static void CreateProperty<T>(TypeBuilder typeBuilder, string propertyNa
currSetIL
.
Emit
(
OpCodes
.
Call
,
setIsDirtyMethod
);
currSetIL
.
Emit
(
OpCodes
.
Ret
);
//TODO: Should copy all attributes defined by the interface?
if
(
isIdentity
)
{
Type
keyAttribute
=
typeof
(
KeyAttribute
);
// Create a Constructorinfo object for attribute 'MyAttribute1'.
ConstructorInfo
myConstructorInfo
=
keyAttribute
.
GetConstructor
(
new
Type
[]
{
});
// Create the CustomAttribute instance of attribute of type 'MyAttribute1'.
CustomAttributeBuilder
attributeBuilder
=
new
CustomAttributeBuilder
(
myConstructorInfo
,
new
object
[]
{
});
var
keyAttribute
=
typeof
(
KeyAttribute
);
var
myConstructorInfo
=
keyAttribute
.
GetConstructor
(
new
Type
[]
{
});
var
attributeBuilder
=
new
CustomAttributeBuilder
(
myConstructorInfo
,
new
object
[]
{
});
property
.
SetCustomAttribute
(
attributeBuilder
);
}
// Last, we must map the two methods created above to our PropertyBuilder to
// their corresponding behaviors, "get" and "set" respectively.
property
.
SetGetMethod
(
currGetPropMthdBldr
);
property
.
SetSetMethod
(
currSetPropMthdBldr
);
MethodInfo
getMethod
=
typeof
(
T
).
GetMethod
(
"get_"
+
propertyName
);
MethodInfo
setMethod
=
typeof
(
T
).
GetMethod
(
"set_"
+
propertyName
);
var
getMethod
=
typeof
(
T
).
GetMethod
(
"get_"
+
propertyName
);
var
setMethod
=
typeof
(
T
).
GetMethod
(
"set_"
+
propertyName
);
typeBuilder
.
DefineMethodOverride
(
currGetPropMthdBldr
,
getMethod
);
typeBuilder
.
DefineMethodOverride
(
currSetPropMthdBldr
,
setMethod
);
}
...
...
Dapper.Contrib/Extensions/SqlMapperExtensions.cs
View file @
b68362f5
...
...
@@ -2,6 +2,7 @@
using
System.Collections.Generic
;
using
System.ComponentModel.DataAnnotations
;
using
System.Data
;
using
System.Diagnostics
;
using
System.Linq
;
using
System.Reflection
;
using
System.Text
;
...
...
@@ -15,6 +16,7 @@ public static class SqlMapperExtensions
private
static
readonly
ConcurrentDictionary
<
RuntimeTypeHandle
,
IEnumerable
<
PropertyInfo
>>
KeyProperties
=
new
ConcurrentDictionary
<
RuntimeTypeHandle
,
IEnumerable
<
PropertyInfo
>>();
private
static
readonly
ConcurrentDictionary
<
RuntimeTypeHandle
,
IEnumerable
<
PropertyInfo
>>
TypeProperties
=
new
ConcurrentDictionary
<
RuntimeTypeHandle
,
IEnumerable
<
PropertyInfo
>>();
private
static
readonly
ConcurrentDictionary
<
RuntimeTypeHandle
,
string
>
GetQueries
=
new
ConcurrentDictionary
<
RuntimeTypeHandle
,
string
>();
private
static
readonly
ConcurrentDictionary
<
RuntimeTypeHandle
,
string
>
TypeTableName
=
new
ConcurrentDictionary
<
RuntimeTypeHandle
,
string
>();
private
static
IEnumerable
<
PropertyInfo
>
KeyPropertiesCache
(
Type
type
)
{
...
...
@@ -73,13 +75,12 @@ private static IEnumerable<PropertyInfo> TypePropertiesCache(Type type)
throw
new
DataException
(
"Get<T> only supports en entity with a [Key] property"
);
var
onlyKey
=
keys
.
First
();
var
name
=
type
.
Name
;
if
(
type
.
IsInterface
&&
name
.
StartsWith
(
"I"
))
name
=
name
.
Substring
(
1
);
var
name
=
GetTableName
(
type
);
// TODO: pluralizer
// TODO: query information schema and only select fields that are both in information schema and underlying class / interface
sql
=
"select * from "
+
name
+
"
s
where "
+
onlyKey
.
Name
+
" = @id"
;
sql
=
"select * from "
+
name
+
" where "
+
onlyKey
.
Name
+
" = @id"
;
GetQueries
[
type
.
TypeHandle
]
=
sql
;
}
...
...
@@ -112,24 +113,44 @@ private static IEnumerable<PropertyInfo> TypePropertiesCache(Type type)
return
obj
;
}
private
static
string
GetTableName
(
Type
type
)
{
string
name
;
if
(!
TypeTableName
.
TryGetValue
(
type
.
TypeHandle
,
out
name
))
{
name
=
type
.
Name
+
"s"
;
if
(
type
.
IsInterface
&&
name
.
StartsWith
(
"I"
))
name
=
name
.
Substring
(
1
);
//NOTE: This as dynamic trick should be able to handle both our own Table-attribute as well as the one in EntityFramework
var
tableattr
=
type
.
GetCustomAttributes
(
false
).
Where
(
attr
=>
attr
.
GetType
().
Name
==
"TableAttribute"
).
SingleOrDefault
()
as
dynamic
;
if
(
tableattr
!=
null
)
name
=
tableattr
.
Name
;
TypeTableName
[
type
.
TypeHandle
]
=
name
;
}
return
name
;
}
/// <summary>
/// Inserts an entity into table "Ts" and returns identity id.
/// </summary>
/// <param name="connection">Open SqlConnection</param>
/// <param name="entityToInsert">Entity to insert</param>
/// <returns>Identity of inserted entity</returns>
public
static
long
Insert
<
T
>(
this
IDbConnection
connection
,
T
entityToInsert
)
public
static
long
Insert
<
T
>(
this
IDbConnection
connection
,
T
entityToInsert
)
where
T
:
class
{
using
(
var
tx
=
connection
.
BeginTransaction
())
{
var
name
=
entityToInsert
.
GetType
().
Name
;
var
type
=
typeof
(
T
);
var
name
=
GetTableName
(
type
);
var
sb
=
new
StringBuilder
(
null
);
sb
.
AppendFormat
(
"insert into {0}
s
("
,
name
);
sb
.
AppendFormat
(
"insert into {0} ("
,
name
);
var
allProperties
=
TypePropertiesCache
(
type
of
(
T
)
);
var
keyProperties
=
KeyPropertiesCache
(
type
of
(
T
)
);
var
allProperties
=
TypePropertiesCache
(
type
);
var
keyProperties
=
KeyPropertiesCache
(
type
);
for
(
var
i
=
0
;
i
<
allProperties
.
Count
();
i
++)
{
...
...
@@ -166,7 +187,7 @@ public static long Insert<T>(this IDbConnection connection, T entityToInsert)
/// <param name="connection">Open SqlConnection</param>
/// <param name="entityToUpdate">Entity to be updated</param>
/// <returns>true if updated, false if not found or not modified (tracked entities)</returns>
public
static
bool
Update
<
T
>(
this
IDbConnection
connection
,
T
entityToUpdate
)
public
static
bool
Update
<
T
>(
this
IDbConnection
connection
,
T
entityToUpdate
)
where
T
:
class
{
var
proxy
=
entityToUpdate
as
IProxy
;
if
(
proxy
!=
null
)
...
...
@@ -180,12 +201,10 @@ public static bool Update<T>(this IDbConnection connection, T entityToUpdate)
if
(
keyProperties
.
Count
()
==
0
)
throw
new
ArgumentException
(
"Entity must have at least one [Key] property"
);
var
name
=
type
.
Name
;
if
(
type
.
IsInterface
&&
name
.
StartsWith
(
"I"
))
name
=
name
.
Substring
(
1
);
var
name
=
GetTableName
(
type
);
var
sb
=
new
StringBuilder
();
sb
.
AppendFormat
(
"update {0}
s
set "
,
name
);
sb
.
AppendFormat
(
"update {0} set "
,
name
);
var
allProperties
=
TypePropertiesCache
(
type
);
var
nonIdProps
=
allProperties
.
Where
(
a
=>
!
keyProperties
.
Contains
(
a
));
...
...
@@ -216,7 +235,7 @@ public static bool Update<T>(this IDbConnection connection, T entityToUpdate)
/// <param name="connection">Open SqlConnection</param>
/// <param name="entityToDelete">Entity to delete</param>
/// <returns>true if deleted, false if not found</returns>
public
static
bool
Delete
<
T
>(
this
IDbConnection
connection
,
T
entityToDelete
)
public
static
bool
Delete
<
T
>(
this
IDbConnection
connection
,
T
entityToDelete
)
where
T
:
class
{
var
type
=
typeof
(
T
);
...
...
@@ -224,12 +243,10 @@ public static bool Delete<T>(this IDbConnection connection, T entityToDelete)
if
(
keyProperties
.
Count
()
==
0
)
throw
new
ArgumentException
(
"Entity must have at least one [Key] property"
);
var
name
=
type
.
Name
;
if
(
type
.
IsInterface
&&
name
.
StartsWith
(
"I"
))
name
=
name
.
Substring
(
1
);
var
name
=
GetTableName
(
type
);
var
sb
=
new
StringBuilder
();
sb
.
AppendFormat
(
"delete from {0}
s
where "
,
name
);
sb
.
AppendFormat
(
"delete from {0} where "
,
name
);
for
(
var
i
=
0
;
i
<
keyProperties
.
Count
();
i
++)
{
...
...
@@ -242,4 +259,14 @@ public static bool Delete<T>(this IDbConnection connection, T entityToDelete)
return
deleted
>
0
;
}
}
[
AttributeUsage
(
AttributeTargets
.
Class
)]
public
class
TableAttribute
:
Attribute
{
public
TableAttribute
(
string
tableName
)
{
Name
=
tableName
;
}
public
string
Name
{
get
;
private
set
;
}
}
}
Dapper.Contrib/Extensions/TypeExtension.cs
View file @
b68362f5
...
...
@@ -2,7 +2,7 @@
using
System.Linq
;
using
System.Runtime.CompilerServices
;
namespace
Dapper.Contrib
namespace
Dapper.Contrib
.Extensions
{
public
static
class
TypeExtension
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment