Skip to content

Commit

Permalink
Merge pull request #72 from GeeseCorp/61--migrate-from-ef-core-to-dapper
Browse files Browse the repository at this point in the history
Fully replaced EF UserManager with Dapper UserProvider.
  • Loading branch information
LemonsLover authored Feb 13, 2024
2 parents ffa1f57 + fcae42e commit 46366ec
Show file tree
Hide file tree
Showing 30 changed files with 322 additions and 187 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static IServiceCollection AddDapperServices(this IServiceCollection servi

private static IServiceCollection AddProviders(this IServiceCollection services)
{
services.AddScoped<UserProvider>();
services.AddSingleton<UserProvider>();


return services;
Expand Down
53 changes: 36 additions & 17 deletions Geesemon.DataAccess.Dapper/Providers/BaseProvider.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Dapper;

using Geesemon.Model.Common;
using Geesemon.Model.Models;

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
Expand All @@ -18,19 +19,19 @@ public BaseProvider(DapperConnection dapperConnection)
this.dapperConnection = dapperConnection;
}

public async Task<bool> CreateAsync(T entity)
public async Task<T> CreateAsync(T entity)
{
using var connection = dapperConnection.Open();
int rowsEffected = 0;

var tableName = GetTableName();
var columns = GetColumns(excludeKey: true);
var properties = GetPropertyNames(excludeKey: true);
var columns = GetColumns();
var properties = GetPropertyNames();
var query = $"INSERT INTO {tableName} ({columns}) VALUES ({properties})";

rowsEffected = await connection.ExecuteAsync(query, entity);

return rowsEffected > 0 ? true : false;
return rowsEffected > 0 ? entity : throw new Exception($"Failed to create {nameof(T)} entity in database.");
}

public async Task<bool> RemoveAsync(T entity)
Expand Down Expand Up @@ -77,7 +78,32 @@ public async Task<T> GetByIdAsync(Guid Id)
return result.FirstOrDefault();
}

public async Task<bool> UpdateAsync(T entity)
public async Task<IEnumerable<T>> GetByIdsAsync(Guid[] Ids)
{
if (Ids.Length == 0)
return Enumerable.Empty<T>();

using var connection = dapperConnection.Open();
IEnumerable<T> result = null;

var tableName = GetTableName();
var keyColumn = GetKeyColumnName();

var whereParts = Ids.Select(id => $"{keyColumn} = '{id}'");

var query = $"SELECT * FROM {tableName} WHERE " + string.Join(" OR ", whereParts);

result = await connection.QueryAsync<T>(query);

return result;
}

public Task<IEnumerable<T>> GetByIdsAsync(IEnumerable<Guid> Ids)
{
return GetByIdsAsync(Ids.ToArray());
}

public async Task<T> UpdateAsync(T entity)
{
using var connection = dapperConnection.Open();
int rowsEffected = 0;
Expand Down Expand Up @@ -106,7 +132,7 @@ public async Task<bool> UpdateAsync(T entity)
rowsEffected = await connection.ExecuteAsync(query.ToString(), entity);


return rowsEffected > 0 ? true : false;
return rowsEffected > 0 ? entity : throw new Exception($"Failed to create {nameof(T)} entity in database.");
}

protected string GetTableName()
Expand All @@ -125,11 +151,11 @@ protected string GetColumns(bool excludeKey = false)
{
var type = typeof(T);
var columns = string.Join(", ", type.GetProperties()
.Where(p => !excludeKey || !p.IsDefined(typeof(KeyAttribute)))
.Where(p => !p.IsDefined(typeof(NotMappedAttribute)) && !p.IsDefined(typeof(DapperNotMappedAttribute)) && (!excludeKey || !p.IsDefined(typeof(KeyAttribute))))
.Select(p =>
{
var columnAttr = p.GetCustomAttribute<ColumnAttribute>();
return columnAttr != null ? columnAttr.Name : p.Name;
return columnAttr != null ? GetTableName() + '.' + columnAttr.Name : p.Name;
}));

return columns;
Expand All @@ -138,7 +164,7 @@ protected string GetColumns(bool excludeKey = false)
protected string GetPropertyNames(bool excludeKey = false)
{
var properties = typeof(T).GetProperties()
.Where(p => !excludeKey || p.GetCustomAttribute<KeyAttribute>() == null);
.Where(p => !p.IsDefined(typeof(NotMappedAttribute)) && !p.IsDefined(typeof(DapperNotMappedAttribute)) && (!excludeKey || p.GetCustomAttribute<KeyAttribute>() == null));

var values = string.Join(", ", properties.Select(p =>
{
Expand All @@ -151,7 +177,7 @@ protected string GetPropertyNames(bool excludeKey = false)
protected IEnumerable<PropertyInfo> GetProperties(bool excludeKey = false)
{
var properties = typeof(T).GetProperties()
.Where(p => !excludeKey || p.GetCustomAttribute<KeyAttribute>() == null);
.Where(p => !p.IsDefined(typeof(NotMappedAttribute)) && !p.IsDefined(typeof(DapperNotMappedAttribute)) && (!excludeKey || p.GetCustomAttribute<KeyAttribute>() == null));

return properties;
}
Expand Down Expand Up @@ -194,12 +220,5 @@ protected static string GetKeyColumnName()

return null;
}

protected static string GetColumnName(PropertyInfo property)
{
var columnAttr = property.GetCustomAttribute<ColumnAttribute>();

return columnAttr != null ? columnAttr.Name : property.Name;
}
}

77 changes: 75 additions & 2 deletions Geesemon.DataAccess.Dapper/Providers/UserProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ public UserProvider(DapperConnection dapperConnection)
public async Task<List<User>> GetAsync(int take, int skip, string searchQuery, Guid? currentUserId = null)
{
using var connection = dapperConnection.Open();
IEnumerable<User> result = null;

var tableName = GetTableName();
var query =
Expand All @@ -22,7 +21,81 @@ public async Task<List<User>> GetAsync(int take, int skip, string searchQuery, G
OFFSET @skip ROWS
FETCH NEXT @take ROWS ONLY;";

result = await connection.QueryAsync<User>(query, new { take, skip, searchQuery, currentUserId });
var result = await connection.QueryAsync<User>(query, new { take, skip, searchQuery, currentUserId });

return result.ToList();
}

public async Task<User?> GetByIdentifierAsync(string identifier)
{
using var connection = dapperConnection.Open();

var tableName = GetTableName();
var query = $"SELECT * FROM {tableName} WHERE Identifier = @identifier";

return await connection.QuerySingleOrDefaultAsync<User>(query, new { identifier });
}

public async Task<User?> GetByEmailAsync(string email)
{
using var connection = dapperConnection.Open();

var tableName = GetTableName();
var query = $"SELECT * FROM {tableName} WHERE Identifier = @email";

return await connection.QuerySingleOrDefaultAsync<User?>(query, new { email });
}

public async Task<List<User>> GetReadByAsync(Guid messageId, int skip, int take)
{
using var connection = dapperConnection.Open();

var tableName = GetTableName();
var columns = GetColumns();
var query =
$@"SELECT {columns}, ReadMessages.[CreatedAt] FROM ReadMessages
INNER JOIN {tableName}
ON {tableName}.Id = ReadMessages.ReadById
WHERE(MessageId = @messageId)
ORDER BY ReadMessages.[CreatedAt] desc
OFFSET @skip ROWS
FETCH NEXT @take ROWS ONLY;";

var result = await connection.QueryAsync<User>(query, new { take, skip, messageId });

return result.ToList();
}

public async Task<int> GetReadByCountByAsync(Guid messageId)
{
using var connection = dapperConnection.Open();

var tableName = GetTableName();
var query =
$@"SELECT COUNT(*) FROM ReadMessages
INNER JOIN {tableName}
ON {tableName}.Id = ReadMessages.ReadById
WHERE(MessageId = @messageId)";

var result = await connection.ExecuteScalarAsync<int>(query, new { messageId });

return result;
}

public async Task<List<User>> GetAsync(Guid chatId)
{
using var connection = dapperConnection.Open();

var tableName = GetTableName();
var columns = GetColumns();
var query =
$@"SELECT {columns} FROM UserChats
INNER JOIN {tableName}
ON {tableName}.Id = UserChats.UserId
WHERE(ChatId = @chatId)
";

var result = await connection.QueryAsync<User>(query, new { chatId });

return result.ToList();
}
Expand Down
4 changes: 2 additions & 2 deletions Geesemon.DataAccess/AppDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@ private void InitEntities()
if (entity is Chat)
{
var chat = (Chat)entity;
chat.ImageColor = colors[rnd.Next(0, colors.Count - 1)];
chat.ImageColor = ColorGenerator.GetRandomColor();
}

if (entity is User)
{
var user = (User)entity;
user.AvatarColor = colors[rnd.Next(0, colors.Count - 1)];
user.AvatarColor = ColorGenerator.GetRandomColor();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Geesemon.DataAccess.Managers;

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

Expand All @@ -12,7 +13,6 @@ public static IServiceCollection AddMsSql(this IServiceCollection services, stri
options.UseSqlServer(connectionString ?? AppDbContext.DefaultConnectionString, b => b.MigrationsAssembly("Geesemon.DataAccess"));
});

services.AddScoped<UserManager>();
services.AddScoped<ChatManager>();
services.AddScoped<MessageManager>();
services.AddScoped<UserChatManager>();
Expand Down
18 changes: 7 additions & 11 deletions Geesemon.DataAccess/Managers/UserManager.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
using Geesemon.DataAccess.Providers.UserProvider;
using Geesemon.Model.Enums;
using Geesemon.Model.Models;

namespace Geesemon.DataAccess.Managers
namespace Geesemon.DataAccess.Managers
{
public class UserManager : UserProvider, IManager<User>
{
public UserManager(AppDbContext appContext)
: base(appContext)
{ }
}
//public class UserManager : UserProvider, IManager<User>
//{
// public UserManager(AppDbContext appContext)
// : base(appContext)
// { }
//}
}
114 changes: 57 additions & 57 deletions Geesemon.DataAccess/Providers/UserProvider/UserProvider.cs
Original file line number Diff line number Diff line change
@@ -1,67 +1,67 @@
using Geesemon.Model.Models;
//using Geesemon.Model.Models;

using Microsoft.EntityFrameworkCore;
//using Microsoft.EntityFrameworkCore;

using System.Linq.Expressions;
//using System.Linq.Expressions;

namespace Geesemon.DataAccess.Providers.UserProvider
{
public class UserProvider : ProviderBase<User>
{
//namespace Geesemon.DataAccess.Providers.UserProvider
//{
// public class UserProvider : ProviderBase<User>
// {

public UserProvider(AppDbContext appDbContext)
: base(appDbContext)
{
}
// public UserProvider(AppDbContext appDbContext)
// : base(appDbContext)
// {
// }

public Task<List<User>> GetReadByAsync(Guid messageId, int skip, int take)
{
return context.ReadMessages
.Include(rm => rm.ReadBy)
.Where(rm => rm.MessageId == messageId)
.OrderByDescending(rm => rm.CreatedAt)
.Skip(skip)
.Take(take)
.Select(rm => rm.ReadBy)
.ToListAsync();
}
// public Task<List<User>> GetReadByAsync(Guid messageId, int skip, int take)
// {
// return context.ReadMessages
// .Include(rm => rm.ReadBy)
// .Where(rm => rm.MessageId == messageId)
// .OrderByDescending(rm => rm.CreatedAt)
// .Skip(skip)
// .Take(take)
// .Select(rm => rm.ReadBy)
// .ToListAsync();
// }

public Task<int> GetReadByCountByAsync(Guid messageId)
{
return context.ReadMessages
.CountAsync(rm => rm.MessageId == messageId);
}
// public Task<int> GetReadByCountByAsync(Guid messageId)
// {
// return context.ReadMessages
// .CountAsync(rm => rm.MessageId == messageId);
// }

public virtual Task<User?> GetByIdentifierAsync(string identifier, params Expression<Func<User, object>>[] includes)
{
return includes.Aggregate(context.Users.AsQueryable(),
(current, include) => current.Include(include))
.FirstOrDefaultAsync(e => e.Identifier == identifier);
}
// public virtual Task<User?> GetByIdentifierAsync(string identifier, params Expression<Func<User, object>>[] includes)
// {
// return includes.Aggregate(context.Users.AsQueryable(),
// (current, include) => current.Include(include))
// .FirstOrDefaultAsync(e => e.Identifier == identifier);
// }

public virtual Task<User?> GetByEmailAsync(string email, params Expression<Func<User, object>>[] includes)
{
return includes.Aggregate(context.Users.AsQueryable(),
(current, include) => current.Include(include))
.FirstOrDefaultAsync(e => e.Email == email);
}
// public virtual Task<User?> GetByEmailAsync(string email, params Expression<Func<User, object>>[] includes)
// {
// return includes.Aggregate(context.Users.AsQueryable(),
// (current, include) => current.Include(include))
// .FirstOrDefaultAsync(e => e.Email == email);
// }

public Task<List<User>> GetAsync(Guid chatId)
{
return context.Users.Include(c => c.UserChats)
.Where(c => c.UserChats.Any(uc => uc.ChatId == chatId))
.ToListAsync();
}
// public Task<List<User>> GetAsync(Guid chatId)
// {
// return context.Users.Include(c => c.UserChats)
// .Where(c => c.UserChats.Any(uc => uc.ChatId == chatId))
// .ToListAsync();
// }

public Task<List<User>> GetAsync(int take, int skip, string q, Guid? currentUserId = null)
{
return context.Users
.Where(u => (u.Identifier.Contains(q) || (u.Email != null && u.Email.Contains(q))) && u.Id != currentUserId)
.OrderBy(u => u.FirstName)
.ThenBy(u => u.LastName)
.Skip(skip)
.Take(take)
.ToListAsync();
}
}
}
// public Task<List<User>> GetAsync(int take, int skip, string q, Guid? currentUserId = null)
// {
// return context.Users
// .Where(u => (u.Identifier.Contains(q) || (u.Email != null && u.Email.Contains(q))) && u.Id != currentUserId)
// .OrderBy(u => u.FirstName)
// .ThenBy(u => u.LastName)
// .Skip(skip)
// .Take(take)
// .ToListAsync();
// }
// }
//}
Loading

0 comments on commit 46366ec

Please sign in to comment.