GithubHelp home page GithubHelp logo

ericdc1 / dapper.simplecrud Goto Github PK

View Code? Open in Web Editor NEW
1.1K 1.1K 420.0 7.84 MB

Who wants to write basic read/insert/update/delete statements? SimpleCRUD provides simple CRUD helpers for Dapper.

License: Other

C# 87.87% Pascal 12.08% Batchfile 0.05%

dapper.simplecrud's Introduction

Dapper.SimpleCRUD - simple CRUD helpers for Dapper

Features

SimpleCRUD

Dapper.SimpleCRUD is a [single file](https://github.com/ericdc1/Dapper.SimpleCRUD/blob/master/Dapper.SimpleCRUD/SimpleCRUD.cs) you can drop in to your project that will extend your IDbConnection interface. (If you want dynamic support, you need an [additional file](https://github.com/ericdc1/Dapper.SimpleCRUD/blob/master/Dapper.SimpleCRUD/SimpleCRUDAsync.cs).)

Who wants to write basic read/insert/update/delete statements?

The existing Dapper extensions did not fit my ideal pattern. I wanted simple CRUD operations with smart defaults without anything extra. I also wanted to have models with additional properties that did not directly map to the database. For example - a FullName property that combines FirstName and LastName in its getter - and not add FullName to the Insert and Update statements.

I wanted the primary key column to be Id in most cases but allow overriding with an attribute.

Finally, I wanted the table name to match the class name by default but allow overriding with an attribute.

This extension adds the following 8 helpers:

  • Get(id) - gets one record based on the primary key
  • GetList<Type>() - gets list of records all records from a table
  • GetList<Type>(anonymous object for where clause) - gets list of all records matching the where options
  • GetList<Type>(string for conditions, anonymous object with parameters) - gets list of all records matching the conditions
  • GetListPaged<Type>(int pagenumber, int itemsperpage, string for conditions, string for order, anonymous object with parameters) - gets paged list of all records matching the conditions
  • Insert(entity) - Inserts a record and returns the new primary key (assumes int primary key)
  • Insert<Guid,T>(entity) - Inserts a record and returns the new guid primary key
  • Update(entity) - Updates a record
  • Delete<Type>(id) - Deletes a record based on primary key
  • Delete(entity) - Deletes a record based on the typed entity
  • DeleteList<Type>(anonymous object for where clause) - deletes all records matching the where options
  • DeleteList<Type>(string for conditions, anonymous object with parameters) - deletes list of all records matching the conditions
  • RecordCount<Type>(string for conditions,anonymous object with parameters) -gets count of all records matching the conditions

For projects targeting .NET 4.5 or later, the following 8 helpers exist for async operations:

  • GetAsync(id) - gets one record based on the primary key
  • GetListAsync<Type>() - gets list of records all records from a table
  • GetListAsync<Type>(anonymous object for where clause) - gets list of all records matching the where options
  • GetListAsync<Type>(string for conditions, anonymous object with parameters) - gets list of all records matching the conditions
  • GetListPagedAsync<Type>(int pagenumber, int itemsperpage, string for conditions, string for order, anonymous object with parameters) - gets paged list of all records matching the conditions
  • InsertAsync(entity) - Inserts a record and returns the new primary key (assumes int primary key)
  • InsertAsync<Guid,T>(entity) - Inserts a record and returns the new guid primary key
  • UpdateAsync(entity) - Updates a record
  • DeleteAsync<Type>(id) - Deletes a record based on primary key
  • DeleteAsync(entity) - Deletes a record based on the typed entity
  • DeleteListAsync<Type>(anonymous object for where clause) - deletes all records matching the where options
  • DeleteListAsync<Type>(string for conditions, anonymous object with parameters) - deletes list of all records matching the conditions
  • RecordCountAsync<Type>(string for conditions, anonymous object with parameters) -gets count of all records matching the conditions

If you need something more complex use Dapper's Query or Execute methods!

Note: all extension methods assume the connection is already open, they will fail if the connection is closed.

Install via NuGet - https://nuget.org/packages/Dapper.SimpleCRUD

Check out the model generator T4 template to generate your POCOs. Documentation is at https://github.com/ericdc1/Dapper.SimpleCRUD/wiki/T4-Template

Get a single record mapped to a strongly typed object

 public static T Get<T>(this IDbConnection connection, int id)

Example basic usage:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}
      
var user = connection.Get<User>(1);   

Results in executing this SQL

Select Id, Name, Age from [User] where Id = 1 

More complex example:

    [Table("Users")]
    public class User
    {
        [Key]
        public int UserId { get; set; }
        [Column("strFirstName")]
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int Age { get; set; }
    }
    
    var user = connection.Get<User>(1);  

Results in executing this SQL

Select UserId, strFirstName as FirstName, LastName, Age from [Users] where UserId = @UserID

Notes:

  • The [Key] attribute can be used from the Dapper namespace or from System.ComponentModel.DataAnnotations

  • The [Table] attribute can be used from the Dapper namespace, System.ComponentModel.DataAnnotations.Schema, or System.Data.Linq.Mapping - By default the database table name will match the model name but it can be overridden with this.

  • The [Column] attribute can be used from the Dapper namespace, System.ComponentModel.DataAnnotations.Schema, or System.Data.Linq.Mapping - By default the column name will match the property name but it can be overridden with this. You can even use the model property names in the where clause anonymous object and SimpleCRUD will generate a proper where clause to match the database based on the column attribute

  • GUID (uniqueidentifier) primary keys are supported (autopopulates if no value is passed in)

Execute a query and map the results to a strongly typed List

public static IEnumerable<T> GetList<T>(this IDbConnection connection)

Example usage:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}
var user = connection.GetList<User>();  

Results in

Select * from [User]

Execute a query with where conditions and map the results to a strongly typed List

public static IEnumerable<T> GetList<T>(this IDbConnection connection, object whereConditions)

Example usage:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}
  
var user = connection.GetList<User>(new { Age = 10 });  

Results in

Select * from [User] where Age = @Age

Notes:

  • To get all records use an empty anonymous object - new{}
  • The where options are mapped as "where [name] = [value]"
  • If you need > < like, etc simply use the manual where clause method or Dapper's Query method
  • By default the select statement would include all properties in the class - The IgnoreSelect attributes remove items from the select statement

Execute a query with a where clause and map the results to a strongly typed List

public static IEnumerable<T> GetList<T>(this IDbConnection connection, string conditions, object parameters = null)

Example usage:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}
  
var user = connection.GetList<User>("where age = 10 or Name like '%Smith%'");  

or with parameters

var encodeForLike = term => term.Replace("[", "[[]").Replace("%", "[%]");
string likename = "%" + encodeForLike("Smith") + "%";
var user = connection.GetList<User>("where age = @Age or Name like @Name", new {Age = 10, Name = likename});  

Results in

Select * from [User] where age = 10 or Name like '%Smith%'

Notes:

  • This uses your raw SQL so be careful to not create SQL injection holes or use the Parameters option
  • There is nothing stopping you from adding an order by clause using this method

Execute a query with a where clause and map the results to a strongly typed List with Paging

public static IEnumerable<T> GetListPaged<T>(this IDbConnection connection, int pageNumber, int rowsPerPage, string conditions, string orderby, object parameters = null)

Example usage:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}
  
var user = connection.GetListPaged<User>(1,10,"where age = 10 or Name like '%Smith%'","Name desc");  

Results in (SQL Server dialect)

SELECT * FROM (SELECT ROW_NUMBER() OVER(ORDER BY Name desc) AS PagedNumber, Id, Name, Age FROM [User] where age = 10 or Name like '%Smith%') AS u WHERE PagedNUMBER BETWEEN ((1 - 1) * 10 + 1) AND (1 * 10)

or with parameters

var user = connection.GetListPaged<User>(1,10,"where age = @Age","Name desc", new {Age = 10});  

Results in (SQL Server dialect)

SELECT * FROM (SELECT ROW_NUMBER() OVER(ORDER BY Name desc) AS PagedNumber, Id, Name, Age FROM [User] where age = 10) AS u WHERE PagedNUMBER BETWEEN ((1 - 1) * 10 + 1) AND (1 * 10)

Notes:

  • This uses your raw SQL so be careful to not create SQL injection holes or use the Parameters option
  • It is recommended to use https://github.com/martijnboland/MvcPaging for the paging helper for your views
    • @Html.Pager(10, 1, 100) - items per page, page number, total records

Insert a record

public static int Insert(this IDbConnection connection, object entityToInsert)

Example usage:

[Table("Users")]
public class User
{
   [Key]
   public int UserId { get; set; }
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public int Age { get; set; }

   //Additional properties not in database
   [Editable(false)]
   public string FullName { get { return string.Format("{0} {1}", FirstName, LastName); } }
   public List<User> Friends { get; set; }
   [ReadOnly(true)]
   public DateTime CreatedDate { get; set; }
}

var newId = connection.Insert(new User { FirstName = "User", LastName = "Person",  Age = 10 });  

Results in executing this SQL

Insert into [Users] (FirstName, LastName, Age) VALUES (@FirstName, @LastName, @Age)

Notes:

  • Default table name would match the class name - The Table attribute overrides this
  • Default primary key would be Id - The Key attribute overrides this
  • By default the insert statement would include all properties in the class - The Editable(false), ReadOnly(true), and IgnoreInsert attributes remove items from the insert statement
  • Properties decorated with ReadOnly(true) are only used for selects
  • Complex types are not included in the insert statement - This keeps the List out of the insert even without the Editable attribute. You can include complex types if you decorate them with Editable(true). This is useful for enumerators.

Insert a record with Guid key

public static int Insert<Guid,T>(this IDbConnection connection, object entityToInsert)

Example usage:

[Table("Users")]
public class User
{
   [Key]
   public Guid GuidKey { get; set; }
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public int Age { get; set; }
}

var newGuid = connection.Insert<Guid,User>(new User { FirstName = "User", LastName = "Person",  Age = 10 });  

Results in executing this SQL

Insert into [Users] (FirstName, LastName, Age) VALUES (@FirstName, @LastName, @Age)

Update a record

public static int Update(this IDbConnection connection, object entityToUpdate)

Example usage:

[Table("Users")]
public class User
{
   [Key]
   public int UserId { get; set; }
   [Column("strFirstName")]
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public int Age { get; set; }

   //Additional properties not in database
   [Editable(false)]
   public string FullName { get { return string.Format("{0} {1}", FirstName, LastName); } }
   public List<User> Friends { get; set; }
}
connection.Update(entity);

Results in executing this SQL

Update [Users] Set (strFirstName=@FirstName, LastName=@LastName, Age=@Age) Where ID = @ID

Notes:

  • By default the update statement would include all properties in the class - The Editable(false), ReadOnly(true), and IgnoreUpdate attributes remove items from the update statement

Delete a record

public static int Delete<T>(this IDbConnection connection, int Id)

Example usage:

public class User
{
   public int Id { get; set; }
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public int Age { get; set; }
}
connection.Delete<User>(newid);

Or

public static int Delete<T>(this IDbConnection connection, T entityToDelete)

Example usage:

public class User
{
   public int Id { get; set; }
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public int Age { get; set; }
}

connection.Delete(entity);

Results in executing this SQL

Delete From [User] Where ID = @ID

Delete multiple records with where conditions

public static int DeleteList<T>(this IDbConnection connection, object whereConditions, IDbTransaction transaction = null, int? commandTimeout = null)

Example usage:

connection.DeleteList<User>(new { Age = 10 });

Delete multiple records with where clause

public static int DeleteList<T>(this IDbConnection connection, string conditions, object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null)

Example usage:

connection.DeleteList<User>("Where age > 20");

or with parameters

connection.DeleteList<User>("Where age > @Age", new {Age = 20});

Get count of records

public static int RecordCount<T>(this IDbConnection connection, string conditions = "", object parameters = null)

Example usage:

var count = connection.RecordCount<User>("Where age > 20");

or with parameters

var count = connection.RecordCount<User>("Where age > @Age", new {Age = 20});

Custom table and column name resolvers

You can also change the format of table and column names, first create a class implimenting the ITableNameResolver and/or IColumnNameResolver interfaces

public class CustomResolver : SimpleCRUD.ITableNameResolver, SimpleCRUD.IColumnNameResolver
{
    public string ResolveTableName(Type type)
    {
        return string.Format("tbl_{0}", type.Name);
    }

    public string ResolveColumnName(PropertyInfo propertyInfo)
    {
        return string.Format("{0}_{1}", propertyInfo.DeclaringType.Name, propertyInfo.Name);
    }
}

then apply the resolvers when intializing your application

    var resolver = new CustomResolver();
    SimpleCRUD.SetTableNameResolver(resolver);
    SimpleCRUD.SetColumnNameResolver(resolver);

Database support

  • There is an option to change database dialect. Default is Microsoft SQL Server but can be changed to PostgreSQL or MySQL. We dropped SQLite support with the .Net Core release.
   SimpleCRUD.SetDialect(SimpleCRUD.Dialect.PostgreSQL);
    
   SimpleCRUD.SetDialect(SimpleCRUD.Dialect.MySQL);

Attributes

The following attributes can be applied to properties in your model

[Table("YourTableName")] - By default the database table name will match the model name but it can be overridden with this.

[Column("YourColumnName"] - By default the column name will match the property name but it can be overridden with this. You can even use the model property names in the where clause anonymous object and SimpleCRUD will generate a proper where clause to match the database based on the column attribute

[Key] -By default the Id integer field is considered the primary key and is excluded from insert. The [Key] attribute lets you specify any Int or Guid as the primary key.

[Required] - By default the [Key] property is not inserted as it is expected to be an autoincremented by the database. You can mark a property as a [Key] and [Required] if you want to specify the value yourself during the insert.

[Editable(false)] - By default the select, insert, and update statements include all properties in the class - The Editable(false) and attribute excludes the property from being included. A good example for this is a FullName property that is derived from combining FirstName and Lastname in the model but the FullName field isn't actually in the database. Complex types are not included in the insert statement - This keeps the List out of the insert even without the Editable attribute.

[ReadOnly(true)] - Properties decorated with ReadOnly(true) are only used for selects and are excluded from inserts and updates. This would be useful for fields like CreatedDate where the database generates the date on insert and you never want to modify it.

[IgnoreSelect] - Excludes the property from selects

[IgnoreInsert] - Excludes the property from inserts

[IgnoreUpdate] - Excludes the property from updates

[NotMapped] - Excludes the property from all operations

Do you have a comprehensive list of examples?

Dapper.SimpleCRUD has a basic test suite in the test project

dapper.simplecrud's People

Contributors

bmeredith avatar devna13 avatar dsau avatar ericdc1 avatar incetarik avatar izhar-ap avatar jafin avatar jdehlin avatar jonathanlarouche avatar leonardosimoura avatar lgirvin avatar michelc avatar mvaz77 avatar opponic avatar peien0312 avatar psantiago avatar satoshiara avatar tim-lukacik avatar xalikoutis avatar yogiraja avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dapper.simplecrud's Issues

Get<T>(this IDbConnection, object) misses transaction as parameter.

Most of SimpleCRUD methods has transaction parameter as optional. Get<T>() has no way to pass transaction so if you do Get<T>() in transaction scope you will get exception:

"ExecuteReader requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized."

please to make SimpleCRUD even more attractive add transaction to get method:

  • Get<T>(this IDbConnection, object, IDbTransaction)

Helper method to only update some field values

I've written an extension that allows me to update only specific fields. If you want to use it, be my guest.

    /// <summary>
    /// Updates table T with the values in param.
    /// The table must have a key named "Id" and the value of id must be included in the "param" anon object. The Id value is used as the "where" clause in the generated SQL
    /// </summary>
    /// <typeparam name="T">Type to update. Translates to table name</typeparam>
    /// <param name="connection"></param>
    /// <param name="param">An anonymous object with key=value types</param>
    /// <returns>The Id of the updated row. If no row was updated or id was not part of fields, returns null</returns>
    public static object UpdateFields<T>(this IDbConnection connection, object param, IDbTransaction transaction = null, int? commandTimeOut = null, CommandType? commandType = null)
    {
        var names = new List<string>();
        object id = null;

        foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(param))
        {
            if (!"Id".Equals(property.Name, StringComparison.InvariantCultureIgnoreCase))
                names.Add(property.Name);
            else
                id = property.GetValue(param);
        }

        if (id != null && names.Count > 0)
        {
            var sql = string.Format("UPDATE {1} SET {0} WHERE Id=@Id", string.Join(",", names.Select(t => { t = t + "=@" + t; return t; })), typeof(T).Name);
            if (Debugger.IsAttached)
                Trace.WriteLine(string.Format("UpdateFields: {0}", sql));
            return connection.Execute(sql, param, transaction, commandTimeOut, commandType) > 0 ? id : null;
        }
        return null;
    }

    public static object UpdateFields<T>(this IDbConnection connection, object fields, CommandDefinition commandDefinition)
    {
        return UpdateFields<T>(connection, fields, commandDefinition.Transaction, commandDefinition.CommandTimeout, commandDefinition.CommandType);
    }

Self-referencing table problem

This table is generated with the ParentPropertyTypeId class property column as PropertyType which is the name of the class and thus fails (there's a fk from ParentPropertyTypeId to Id):

CREATE TABLE [dbo].[PropertyTypes](
[Id] [int] NOT NULL PRIMARY KEY,
[Description] [varchar](50) NOT NULL,
[ParentPropertyTypeId] [int] NULL
) 

Here's what gets generated:

   [Table("PropertyTypes")]
    public partial class PropertyType
    {
    [Key]
    public virtual int Id { get; set; }
    public virtual string Description { get; set; }
    public virtual int? ParentPropertyTypeId { get; set; }
    public virtual PropertyType PropertyType { get; set; }
    public virtual IEnumerable<PropertyPropertyType> PropertyPropertyTypes { get; set; }
    public virtual IEnumerable<PropertyType> PropertyTypes { get; set; }
    }

It seems like this problem would occur on any self-referencing table.

The EF Reverse Poco Generator generates this same table like this:

// PropertyTypes
[GeneratedCodeAttribute("EF.Reverse.POCO.Generator", "2.15.1.0")]
public partial class PropertyType
{
    public int Id { get; set; } // Id (Primary key)
    public string Description { get; set; } // Description
    public int? ParentPropertyTypeId { get; set; } // ParentPropertyTypeId

    // Reverse navigation
    public virtual ICollection<PropertyPropertyType> PropertyPropertyTypes { get; set; } // Many to many mapping
    public virtual ICollection<PropertyType> PropertyTypes { get; set; } // PropertyTypes.FK_PropertyTypes_ParentTypes

    // Foreign keys
    public virtual PropertyType PropertyType_ParentPropertyTypeId { get; set; } // FK_PropertyTypes_ParentTypes

    public PropertyType()
    {
        PropertyPropertyTypes = new List<PropertyPropertyType>();
        PropertyTypes = new List<PropertyType>();
        InitializePartial();
    }

    partial void InitializePartial();
}

I am going to dig deeper but I thought I'd give you a heads up.

Generate "IS NULL" for nullable types with value of null

Hi,

First of all thanks for creating such a handy utility, I really appreciate your efforts!

Not sure if I can put this question here or not, apologies if it's the wrong place. I asked the full question here: http://stackoverflow.com/questions/33862504/dapper-simplecrud-isnull

Basically wondering if SimpleCRUD can auto-detect that a nullable integer is null and generate an "IS NULL" where clause if it is? Not sure if the functionality exists or not, apologies if I've missed it.

Thanks again,

John

Set identity value after insert

Hi,
Why the inserted identity values does not set to the entity? Is there a reason?
If there is, I think it would be a nice feature for the KeyAttribute.
Something like this:

public class KeyAttribute : Attribute
{
    public bool SetValueAfterInsert { get; set; } = false;
}

Specified cast is not valid exception when the model does not have identity

Model:

public class ClubcardV2
{
[Key]
[Required]
public long ClubcardID { get; set; }
public long CustomerID { get; set; }
public byte? ClubcardType { get; set; }
public byte? ClubcardStatus { get; set; }
}

Insert:

public int? Insert(object entityToInsert, IDbTransaction transaction = null, int? commandTimeout = default(int?))
{
using (IDbConnection cnn = new SqlConnection(_connectionString))
{
return cnn.Insert(entityToInsert, transaction, commandTimeout);
}
}
Stack Trace:
at Dapper.SimpleCRUD.Insert[TKey](IDbConnection connection, Object entityToInsert, IDbTransaction transaction, Nullable1 commandTimeout) in C:\Users\Eric\Documents\GitHub\Dapper.SimpleCRUD\Dapper.SimpleCRUD\SimpleCRUD.cs:line 376 at Dapper.SimpleCRUD.Insert(IDbConnection connection, Object entityToInsert, IDbTransaction transaction, Nullable1 commandTimeout) in C:\Users\Eric\Documents\GitHub\Dapper.SimpleCRUD\Dapper.SimpleCRUD\SimpleCRUD.cs:line 299
at Tesco.Com.SVS.Utils.SQLServerMapperExtensions.Insert(Object entityToInsert, IDbTransaction transaction, Nullable1 commandTimeout) in D:\Final\NGC\Services\NGCDataSetup\Tesco.Com.SVS.Utils\SQLServerMapperExtensions.cs:line 57 at NGCDataSetup.Data.Group.ClubcardV2Store.Create(IEnumerable1 Entities) in D:\Final\NGC\Services\NGCDataSetup\NGCDataSetup.Data\Group\ClubcardV2Store.cs:line 23
at NGCDataSetupAPI.Controllers.EntityController4.Create(IEnumerable1 entityList) in D:\Final\NGC\Services\NGCDataSetup\NGCDataSetupAPI\Controllers\EntityController.cs:line 37

When performing insert the statement fails with the above mentioned exception details. but the record getting inserted. Could somebody help me with this issue.

GetListPaged fail

if the table key column name is different than the entity property name then the generated query is wrong and fails to execute.

Here is the example for GetListPaged(1, 10):

SELECT * FROM (SELECT ROW_NUMBER() OVER(ORDER BY Id) AS PagedNumber, [hMy] as Id,[sName] as Name,[sAddress] as Address,[sCity] as City,[sProvince] as Province FROM [Company] ) AS u WHERE PagedNUMBER BETWEEN ((1-1) * 10 + 1) AND (1 * 10)

Error: "Invalid column name 'Id'."

We need to put the column name in ORDER BY clause instead of the entity property name.

Setting Dialect for different DB

I am not sure if this is issue but let me try :)
I noticed in the SimpleCRUD.cs class that there is no arguments constructor with SetDialect(_dialect); method. Right after this we have:
private static Dialect _dialect = Dialect.SQLServer;

So my question is, should we have constructor with arguments setting the sql server or? I didn't find anything on the documentation so far. I found out this using PostgreSQL, and there was error coming from Insert method "Syntax error near "["". I search through your code and found that encapsulation was issue.
Note: I installed the extension via Nuget.
Note 2: Anyway, awesome work and thanks for your time and effort developing this.

Specify SQL Literal for SQL Builder

In my database, firebird [TABLE] is not valid in

select * from [TABLE]

Only

select * from "TABLE"

Is valid

OR

select * from TABLE

Apart from removing the [] from the stringbuilders for the Table names, and the where clauses, what do you suggest?

Save Id to object in Insert

It would be nice if after Inserting an object the auto Id generated would be saved back to the Id property of the object.

Have a DeleteList

It would be great to have a DeleteList method with a signature comparable to the GetList method:

public static int DeleteList <T>(this IDbConnection connection, object whereConditions)

Bug with WHERE clause in Get method?

Great software - just what I was looking for.

I think I've found a bug though:

In the Get method, when creating the WHERE clause onlyKey.name is used which returns the property name not taking into account that the property might have a Column attribute. Should this instead be: GetColumnName(onlyKey)?

Any hope of a CoreCLR lib

looks like dapper supprorts CoreCLR in at least a beta form, is there any chance of getting a compatible release here?

When Insert, get Long type as return of autoincrement value

Hi @ericdc1,
see #39

I tried your version with my suggested implementation. It run fine but ONLY if the id autoincrement is an integer type. Yes, I known that the integer contain 2.000.000.000+ rows, but this is not known who created the database I'm working. I can't change the type id on table definitions, I must use the long type.
I would mark as deprecated my version https://github.com/clabnet/Dapper.SimpleCRUD of your code, but I can't do it until this feature is not running with this requirements.
Please feel free to contact me for other informations.
Grazie for your work.

Deep clone object is not working with Update

Sir,

Looks like there might be some issue if we use the deep copy of object while updating the entity. I'm using below code

  db.Update(_SelectedItem);

I have extension method for deepclone
public static T DeepClone(this T a)
{
using (MemoryStream stream = new MemoryStream())
{
DataContractSerializer dcs = new DataContractSerializer(typeof(T));
dcs.WriteObject(stream, a);
stream.Position = 0;
return (T)dcs.ReadObject(stream);
}
}

_SelectedItem = MyItem.DeepClone();

Insert with Guid Key

Unable to insert with Guid Key.
Its mentioned as Todo.when it will be implemented
Most of implementation are with Guid so its of no use until Guid support is provided

Primary Key Field Assumes 0 is Default Value

In version 1.9.0, you added the predefined value of 0 for the ID field. I understand why it was added, but can it be handled differently. I (and several other developers I know) use different values for the initialization of the object/field representing the primary key (some use -1, some use int.minValue, etc.). I initialize everything (a holdover from my days of doing C/C++ programming). When a class model is initialized to a default value other than 0, the new identity is not loaded into the primary key field.

Can we create an attribute to determine the default value of the primary key and then compare to that attribute value (instead of hard coding 0)? Thanks -- love your library.

GetPK SQL has bug

T4 Template function GetPK sql
WHERE (i.type = 1) AND (o.name = @tableName)
suggest fix by
WHERE (i.is_primary_key = 1) AND (o.name = @tableName)

Can't insert records in a table N-N (without Id)

When try to insert a record in a table N-N (formed by 2 foreign keys, but non primary key) the Insert method show the legend 'Insert only supports an entity with a [Key] or Id property' (which is correct) and kick-out.
But in this case I don't need get any Id in return, so, I think that can help for tables which don't have any primary key an Insert method that not return any Id, and don't stop. I see a branch 'keylessinsert' but seems old.
In fact a new method Insert without any return will be extremely tiny, just:

public static void Insert(this IDbConnection connection, object entityToInsert, IDbTransaction transaction = null, int? commandTimeout = null)
{
    var name = GetTableName(entityToInsert);
    var sb = new StringBuilder();
    sb.AppendFormat("insert into {0}", name);
    sb.Append(" (");
    BuildInsertParameters(entityToInsert, sb);
    sb.Append(") ");
    sb.Append("values");
    sb.Append(" (");
    BuildInsertValues(entityToInsert, sb);
    sb.Append(")");

    var r = connection.Query(sb.ToString(), entityToInsert, transaction, true, commandTimeout);
}

Do you think in the future add some like that?

The SimpleCRUD is extremely useful, thanks and congratulations!

Oracle dialect support

Has anybody tried to get this working with Oracle? I was able to almost get it working by adding a dialect for Oracle and a global variable _parameterPrefix (Oracle wants ":" not "@"). However the insert returning the new key is causing me issues. I'm going to keep working at it but I don't have a good solution for this yet. If anybody has worked on this issue and has a good solution I'd be interested in your experience.

Triggers cause .Insert to return incorrect Id, @@identity vs scope_identity()

First, I did notice the comment in the source code regarding scope_identity() in the Insert method. But wanted to make you aware (if you were not already) that when using Insert against a table with a trigger that is inserting to another table (audit purposes in this case), and that secondary table has an identity column, using @@identity returns the id from the secondary table. I've considered attempting to maintain a local version of SimpleCRUD and putting the scope_identity() version of the code back in place, but for now have just chosen to work around it. Any plans to switch this out or provide intelligence in SimpleCRUD to resolve and return the correct ID based on the version of SQL Server?

Editable(false) Attribute stops data being selected

I recently updated from an older version, not sure which one, but is this by design to have the Editable(false) attribute prevent the property from being read on the Get?

I have fields such as CreatedDateTime, ModifedDateTime, etc, that I use default value / triggers on the database creating the values which I marked as Editable(false). That way it doesn't attempt to insert or update these fields as I want the DB to manage them. However, when a select is run from any of the Gets the function GetScaffoldableProperties strips out anything with Editable(false) on it so the never gets filled.

As a workaround I created a new function for the selects that wouldn't parse out the Editable(false) properties for the Gets and I was thinking about adding a new attribute to make it a big cleaner and controllable. Thoughts?

Overload for DeleteList<T> to use whereConditions object

Hi,
I'd like to add an overload to the library for both DeleteList<T> and DeleteListAsync<T> to promote the use of the whereConditions object instead of writing out the where-statement in a string. In a similar fashion to what the GetList<T> function does.

Example:

using(var db = GetDbConnection()){
    // will delete all users whose first name is equal to Test
    db.DeleteList<User>(new { Firstname = "Test" })
}

Kind regards,
Elmar

Can't get the ModelGenerator working

I tried copying ModelGenerator.tt into my project and running it against my development database, but nothing gets generated. I also tried using the "SampleWebsite" without modifying it and generating from there, but had the same result.

Is there anything special that needs to be done or should it just work when you "Run Custom Tool"?

Update only modified columns not supported

Hi,

Is there any way to update modified entity columns only?

Currently it's seems if we not set entity property value it will update previous value to either null or empty into database table respected columns rather then just keeping it as previous value.

Paged lists

i have been using simplecrud pretty heavily in my new project. Now am at a point where i need to paginate things. Would love to contribute or get started on pagination. Do you have any ideas or have you started on this as i can see it is in your future feature ideas on the readme.

Why a NuGet package for a proof of concept?

I found this library by searching through the nuget repository and even though I was initially happy by including it in my project, soon enough I realized I made a huge mistake.

Performance is all over the place. From building entities through reflection just to get a list of properties, the lack of static caching for the discovered properties, table names and whatever else for entity types, to little things like enumerating those properties over and over again ( Build* methods) and the list of issues can go on and on.

Was there a reason why you thought this would be a good candidate for a NuGet package?

Why not add oracle samples, other database is a little cake

As so many office side copy everywhere, most of database are similar but oracle and DB2, it contains tablespace, table prefix, transactions, locks, functions, return values, parameter formatting, and so on.

I was trying in the place, hope to see something new here, thanks a lot!

Object Multimapping

Hello, love this library. Is there any hope of building in the ability to use Dapper's multiple object mapping feature. I know that I can call Dapper directly, but I am looking to see if this will be a feature that will be included in an upcoming release? Having the ability to load an object that consists of a mix of simple and complex types could be very useful.

Unable to specify schema

Functions like Get<>() and GetList<>() do not work across different non-default schemas.

A work around is to provide a TableAttribute on the class in this fashion:

[Table("Schema].[Table")]

There might be an extended attributes that allows a fully qualified name (i.e. using three parameters - one for db, one for schema, one for table), or additional attributes such as SchemaAttribute.

Why is default insert functionality not working?

Hi,

Here is a sample of my schema:

[System.ComponentModel.DataAnnotations.Schema.Table("tblUsers")]
public partial class User
{
[Key]
public virtual long ID { get; set; }
public virtual string Title { get; set; }
public virtual string Name { get; set; }
public virtual string Email { get; set; }
public virtual string Username { get; set; }
public virtual string Phone { get; set; }
...

I am trying to do this, per the documentation:

_connection.Insert<User>(user);

However, I get this error message:

"Message":"An error has occurred.","ExceptionMessage":"Invalid return type","ExceptionType":"System.Exception","StackTrace":" at Dapper.SimpleCRUD.Insert[TKey](IDbConnection connection, Object entityToInsert, IDbTransaction transaction, Nullable`1 commandTimeout) in c:_Code\ThirdParty\Dapper.SimpleCRUD\Dapper.SimpleCRUD\SimpleCRUD.cs:line 232\r\n at VIPAthlete.API.Models.UserManager.Insert(User user) in c:_Code\VIPAthlete-Web\VIPAthlete.API\Models\User.cs:line 102\r\n at VIPAthlete.API.Controllers.UsersController.Post(User user) in c:_Code\VIPAthlete-Web\VIPAthlete.API\Controllers\UsersController.cs:line 75"

Doing some digging into the source code, I see this at SimpleCRUD.cs:line 232:

var baseType = typeof(TKey);
var underlyingType = Nullable.GetUnderlyingType(baseType);
var keytype = underlyingType ?? baseType;

In my case, baseType turns out to be "User" and not the Key (which is ID, a 'long' type).

This does solve my problem and works fine:

_connection.Insert<long>(user);

Why doesn't my initial insert line of code work?

Thanks.

Return the ID (primary key) of the newly inserted record even the entity has predefined value

if ((keytype == typeof(int) || keytype == typeof(long)) && Convert.ToInt64(idProps.First().GetValue(entityToInsert, null)) == 0) { sb.Append(";" + _getIdentitySql); }

Could you please change this code (and for other pk types) to be able to get the pk id even the entity has predefined value?
Or we can have any exception, for now the behavior is not good.
It's confusing... To understand why I didn't get a new pk key, I was forced to view a source code.

Allow Entities without PrimaryKey

Currently Each entity we work with must have an Id (Primary Key) property. How can we overcome this limitation and allow insertion without primary key.

TableNameResolver.ResolveTableName(Type type) causes exception in .NET 4.0

Hi,

I used your pretty nice Dapper CRUD implementation on a project that targets .NET 4.0. I noticed that TableNameResolver classes ResolveTableName(Type type) threw an exception about missing method when calling Encapsulate() method on "tableattr.Name" (line 939).
For the reference, I'm using PostgreSQL dialect.

The problem is that it does not consider it as a string without explicitly casting the value as a string and therefore the method signature that takes "string" as a parameter wont match the call. The problem was solved by using the explicit cast.

-> For improved support, consider using explicit casts on cases where you use dynamic properties.

Ignore property on update

Hi,

I have a use case where I need some properties to be inserted but not updated. For example a 'Created' property that never changes after the initial insert (or a company / tenant ID that shouldn't be allowed to be updated). I couldn't find a solution to this, apologies if I missed anything glaringly obvious! I looked at the current property attributes but could only see ones like 'ReadOnly' and 'Editable(false)' which exclude the properties altogether.

Anyway, one workaround was to create a new property attribute called 'IgnoreUpdate'. Properties marked with the 'IgnoreUpdate' attribute will be included during insert but ignored during an update.

Comments welcomed.

Cheers

/// <summary>
/// Optional IgnoreUpdate attribute.
/// Ignores the specified property during an update
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class IgnoreUpdateAttribute : Attribute
{
}
...
private static IEnumerable<PropertyInfo> GetUpdateableProperties(object entity)
{
...
//remove ones with IgnoreUpdate attribute
updateableProperties = updateableProperties.Where(p => p.GetCustomAttributes(true).Any(attr => attr.GetType().Name == "IgnoreUpdateAttribute") == false);

Passing params with complex WHERE clause

There is currently no way to pass params along with a complex where clause. The only way to get around it (that I know of) is to do string concatenation to build the params into the where clause itself. Why can't we pass the params through GetList alongside the where clause?

public static IEnumerable<T> GetList<T>(this IDbConnection connection, string conditions, object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null)
{
    [...]
    return connection.Query<T>(sb.ToString(), parameters, transaction, true, commandTimeout);
}

Then you could do something like:

string whereClause = "WHERE age > @customerAge AND FirstName + ' ' + LastName LIKE '%' + @Name + '%'";
var customers  = conn.GetList<Customer>(whereClause, new { customerAge = 21, Name = "mic" });

I could submit a PR for this if you're interested

Helper method to avoid SQL injection

Hi all!

Thanks for such a great project!

I was working with some POCs and I found that there's a helper missing that could help a lot. The problem was when I was trying to do a select with a like condition.

I know that you already mentioned in the documentation that for using >< and like we should use Dapper's query, but honestly if I go in that way I'll lost all the mappings...

Here's my scenario:
var orgs = connection.GetList("where name like '%" + name + "%'");

As you can imagine this is impossible to use because it's open to SQL injection, so instead of doing that I needed to do the following:

var orgs = connection.Query("select * from organizations where name like @name", new {Name = "'%" + name + "%'"});

But once again, the problem is that I lost all the mappings I created with SimpleCRUD.

So, to fix this situation I needed something like this:

var orgs = connection.GetList("where name like @name", new {Name = "%" + name + "%"});

And because of that I downloaded the SimpleCRUD file and I added my own method. If you think that's helpful and it can be included, be my guest.

Regards.

Mauro

    /// <summary>
    /// <para>By default queries the table matching the class name</para>
    /// <para>-Table name can be overridden by adding an attribute on your class [Table("YourTableName")]</para>
    /// <para>conditions is an SQL where clause and/or order by clause ex: "where name='bob'"</para>
    /// <para>Returns a list of entities that match where conditions</para>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="connection"></param>
    /// <param name="conditions"></param>
    /// <param name="whereParameters"></param>
    /// <returns>Gets a list of entities with optional SQL where conditions</returns>
    public static IEnumerable<T> GetList<T>(this IDbConnection connection, string conditions, object whereParameters)
    {
        var currenttype = typeof(T);
        var idProps = GetIdProperties(currenttype).ToList();
        if (!idProps.Any())
            throw new ArgumentException("Entity must have at least one [Key] property");

        var name = GetTableName(currenttype);

        var sb = new StringBuilder();
        sb.Append("Select ");
        //create a new empty instance of the type to get the base properties
        BuildSelect(sb, GetScaffoldableProperties((T)Activator.CreateInstance(typeof(T))).ToArray());
        sb.AppendFormat(" from {0}", name);

        sb.Append(" " + conditions);

        if (Debugger.IsAttached)
            Trace.WriteLine(String.Format("GetList<{0}>: {1}", currenttype, sb));

        return connection.Query<T>(sb.ToString(), whereParameters);
    }

Not able to update using sqlite

Not able to update the sqlite table using below command

SQLiteConnection connection = new SQLiteConnection(conn);
var user = connection.Get(36);
user.EmailID = "[email protected]";
connection.Update(user);

throwing the error
Error 1 The event 'System.Data.SQLite.SQLiteConnection.Update' can only appear on the left hand side of += or -= C:\Users\SG2057\documents\visual studio 2012\Projects\TestSQLIte\TestSQLIte\Program.cs 24 28 TestSQLIte

Please note: if I use below then works fine
DbConnection connection = new SQLiteConnection(conn);

dotnetcore support?

Hi,

I'm getting this error when trying to target NETStandard:

Dapper itself doesn't seem to have an issue with it. Is this something that can easily be fixed or worked around?

Package Dapper.SimpleCRUD 1.12.0 is not compatible with netstandard1.6 (.NETStandard,Version=v1.6). Package Dapper.SimpleCRUD 1.12.0 supports:
- net40 (.NETFramework,Version=v4.0)
- net45 (.NETFramework,Version=v4.5)

Thanks

Inserting an entity with a manually specified primary key

I have a table with an Id column that is manually specified by my code, rather than being marked as an identity column in SQL Server. Is there any way I can tell SimpleCRUD to not exclude it from the insert? The code appears to check that I have a Key or Id attribute so simply renaming the column won't work.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.