Skip to content

Commit

Permalink
* add ExpressionUtilites
Browse files Browse the repository at this point in the history
* add FillKey method and extension
* rename Commit method to Complete in TransactionService
* add Remove(key) method in IEditRepository
* add Exsist(key) method in IReadRepository and ReadService
  • Loading branch information
vahpetr committed Oct 8, 2015
1 parent 6bcaacf commit 388f214
Show file tree
Hide file tree
Showing 11 changed files with 229 additions and 18 deletions.
1 change: 1 addition & 0 deletions Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
<Compile Include="Services\SecurityService.cs" />
<Compile Include="Services\TransactionService.cs" />
<Compile Include="Utilites\EntityUtilites.cs" />
<Compile Include="Utilites\ExpressionUtilites.cs" />
<Compile Include="Utilites\MappingUtilites.cs" />
<Compile Include="Utilites\ObjectUtilites.cs" />
<Compile Include="Utilites\TypeUtilites.cs" />
Expand Down
62 changes: 53 additions & 9 deletions Extensions/EntityExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@ namespace Common.Extensions
{
public static class EntityExtensions
{
public static TEntity Find<TEntity>(
this IQueryable<TEntity> source,
params object[] keys)
private static Expression<Func<TEntity, bool>> GetExpression<TEntity>(
params object[] key)
where TEntity : class
{
var keyProps = EntityUtilites<TEntity>.KeyProps;
if (keys.Count() != keyProps.Count()) return null;
if (key.Count() != keyProps.Count()) return null;

var entityType = typeof(TEntity);
var entityParameter = Expression.Parameter(entityType, "p");
Expand All @@ -28,7 +27,7 @@ public static TEntity Find<TEntity>(
var genericType = typeof(TypeUtilites<>).MakeGenericType(property.Type);
var tryConvertValue = genericType.GetMethod("TryConvertValue",
new[] { typeof(object), property.Type.MakeByRefType() });
object[] args = { keys[i++], null };
object[] args = { key[i++], null };
var result = (bool)tryConvertValue.Invoke(null, args);
if (!result) return null;
var constant = Expression.Constant(args[1]);
Expand All @@ -39,10 +38,38 @@ public static TEntity Find<TEntity>(
var body = expressions.Aggregate(Expression.And);
var expression = Expression.Lambda<Func<TEntity, bool>>(body, entityParameter);

return expression;
}

public static TEntity Find<TEntity>(
this IQueryable<TEntity> source,
params object[] key)
where TEntity : class
{
var expression = GetExpression<TEntity>(key);

var call = Expression.Call(
typeof(Queryable),
"FirstOrDefault",
new[] { entityType },
new[] { source.ElementType },
source.Expression,
Expression.Quote(expression)
);

return source.Provider.Execute<TEntity>(call);
}

public static TEntity Exist<TEntity>(
this IQueryable<TEntity> source,
params object[] key)
where TEntity : class
{
var expression = GetExpression<TEntity>(key);

var call = Expression.Call(
typeof(Queryable),
"Any",
new[] { source.ElementType },
source.Expression,
Expression.Quote(expression)
);
Expand All @@ -63,15 +90,32 @@ public static TEntity Identity<TEntity>(this TEntity entity) where TEntity : cla
return EntityIdentityUtilites<TEntity>.Identity(entity);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void FillKey<TEntity>(this TEntity entity, params object[] key) where TEntity : class
{
EntityFillKeyUtilite<TEntity>.Mapper(key, entity);
}

public static TEntity Find<TEntity>(
this IEnumerable<TEntity> source,
params object[] keys)
params object[] key)
where TEntity : class
{
var keyProps = EntityUtilites<TEntity>.KeyProps;
if (key.Count() != keyProps.Count()) return null;
var keyEqual = EntityKeyEqualUtilites<TEntity>.KeyEqual;
return source.FirstOrDefault(p => keyEqual(p, key));
}

public static bool Exist<TEntity>(
this IEnumerable<TEntity> source,
params object[] key)
where TEntity : class
{
var keyProps = EntityUtilites<TEntity>.KeyProps;
if (keys.Count() != keyProps.Count()) return null;
if (key.Count() != keyProps.Count()) return false;
var keyEqual = EntityKeyEqualUtilites<TEntity>.KeyEqual;
return source.FirstOrDefault(p => keyEqual(p, keys));
return source.Any(p => keyEqual(p, key));
}
}
}
6 changes: 3 additions & 3 deletions Facades/Facade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public async Task Add(TEntity entity)
{
await edit.Value.AddAsync(entity);
await edit.Value.CommitAsync();
transaction.Value.Commit();
transaction.Value.Complete();
}
catch (Exception)
{
Expand All @@ -69,7 +69,7 @@ public async Task Update(TEntity currEntity, TEntity prevEntity)
{
await edit.Value.UpdateAsync(currEntity, prevEntity);
await edit.Value.CommitAsync();
transaction.Value.Commit();
transaction.Value.Complete();
}
catch (Exception)
{
Expand All @@ -88,7 +88,7 @@ public async Task Remove(TEntity entity)
{
await edit.Value.RemoveAsync(entity);
await edit.Value.CommitAsync();
transaction.Value.Commit();
transaction.Value.Complete();
}
catch (Exception)
{
Expand Down
8 changes: 7 additions & 1 deletion Repositories/Contract/IEditRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Common.Repositories.Contract
/// <summary>
/// Интерфейс храналища редактирования данных
/// </summary>
/// <typeparam name="TEntity">Тип сущьностит</typeparam>
/// <typeparam name="TEntity">Тип сущьностит </typeparam>
public interface IEditRepository<TEntity>
where TEntity : class
{
Expand Down Expand Up @@ -36,6 +36,12 @@ public interface IEditRepository<TEntity>
/// <param name="entity">Сущность</param>
void Remove(TEntity entity);

/// <summary>
/// Удалить сущность
/// </summary>
/// <param name="key">Ключ</param>
void Remove(params object[] key);

/// <summary>
/// Сохранить все изменения
/// </summary>
Expand Down
18 changes: 16 additions & 2 deletions Repositories/Contract/IReadRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ public interface IReadRepository<TEntity, in TFilter>
/// <summary>
/// Получить сущность
/// </summary>
/// <param name="key">Ключ cущности</param>
/// <param name="key">Ключ</param>
/// <returns>Сущность</returns>
TEntity Get(params object[] key);

/// <summary>
/// Асинхронно получить сущность
/// </summary>
/// <param name="key">Ключ cущности</param>
/// <param name="key">Ключ</param>
/// <returns>Сущность</returns>
Task<TEntity> GetAsync(params object[] key);

Expand Down Expand Up @@ -70,6 +70,20 @@ public interface IReadRepository<TEntity, in TFilter>
/// <returns>Логическое значение</returns>
Task<bool> ExistAsync(TFilter filter);

/// <summary>
/// Проверить существуют ли сущности
/// </summary>
/// <param name="key">Ключ</param>
/// <returns>Логическое значение</returns>
bool Exist(params object[] key);

/// <summary>
/// Асинхронно проверить существуют ли сущности
/// </summary>
/// <param name="key">Ключ</param>
/// <returns>Логическое значение</returns>
Task<bool> ExistAsync(params object[] key);

/// <summary>
/// Получить количество сущностей
/// </summary>
Expand Down
16 changes: 15 additions & 1 deletion Services/Contract/IReadService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public interface IReadService<TEntity, in TFilter>
/// <summary>
/// Получить сущность по номеру
/// </summary>
/// <param name="key">Ключ cущности</param>
/// <param name="key">Ключ</param>
/// <returns>Сущность</returns>
TEntity Get(params object[] key);

Expand Down Expand Up @@ -69,6 +69,20 @@ public interface IReadService<TEntity, in TFilter>
/// <returns>Логическое значение</returns>
Task<bool> ExistAsync(TFilter filter);

/// <summary>
/// Проверить существуют ли сущности
/// </summary>
/// <param name="key">Ключ cущности</param>
/// <returns>Логическое значение</returns>
bool Exist(params object[] key);

/// <summary>
/// Асинхронно проверить существуют ли сущности
/// </summary>
/// <param name="key">Ключ cущности</param>
/// <returns>Логическое значение</returns>
Task<bool> ExistAsync(params object[] key);

/// <summary>
/// Получить количество сущностей
/// </summary>
Expand Down
5 changes: 4 additions & 1 deletion Services/Contract/ITransactionService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
namespace Common.Services.Contract
{
/// <summary>
/// Сервис транзакции
/// </summary>
public interface ITransactionService
{
/// <summary>
Expand All @@ -10,7 +13,7 @@ public interface ITransactionService
/// <summary>
/// Завершить транзакцию
/// </summary>
void Commit();
void Complete();

/// <summary>
/// Отменить транзакцию
Expand Down
21 changes: 21 additions & 0 deletions Services/ReadService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,27 @@ public Task<bool> ExistAsync(TFilter filter)
return Task.FromResult(repository.Value.Exist(filter));
}

/// <summary>
/// Проверить существуют ли сущности
/// </summary>
/// <param name="key">Ключ</param>
/// <returns>Логическое значение</returns>
public virtual bool Exist(params object[] key)
{
return repository.Value.Exist(key);
}

/// <summary>
/// Асинхронно проверить существуют ли сущности
/// </summary>
/// <param name="key">Ключ</param>
/// <returns>Логическое значение</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Task<bool> ExistAsync(params object[] key)
{
return Task.FromResult(repository.Value.Exist(key));
}

/// <summary>
/// Получить количество сущностей
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion Services/TransactionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public void Begin()
/// <summary>
/// Завершить транзакцию
/// </summary>
public void Commit()
public void Complete()
{
transaction.Complete();
transaction.Dispose();
Expand Down
38 changes: 38 additions & 0 deletions Utilites/EntityUtilites.cs
Original file line number Diff line number Diff line change
Expand Up @@ -194,4 +194,42 @@ static EntityKeyEqualUtilites()
KeyEqual = EntityKeyEqualExpressionUtilites<TEntity>.KeyEqualExpression.Compile();
}
}

public static class EntityFillKeyExpressionUtilite<TTo> where TTo : class
{
public static readonly Expression<Action<object[], TTo>> Mapper;

static EntityFillKeyExpressionUtilite()
{
var type = typeof(TTo);
var entity = Expression.Parameter(type, "entity");
var array = Expression.Parameter(typeof(object[]), "key");
var expressions = new List<Expression>();
var props = EntityUtilites<TTo>.KeyProps;

var i = 0;
foreach (var prop in props)
{
var value = Expression.ArrayIndex(array, Expression.Constant(i++));
var convert = Expression.Convert(value, prop.PropertyType);
var field = Expression.Property(entity, prop);
var assing = Expression.Assign(field, convert);
expressions.Add(assing);
}

var block = Expression.Block(expressions);

Mapper = Expression.Lambda<Action<object[], TTo>>(block, new[] { array, entity });
}
}

public static class EntityFillKeyUtilite<TTo> where TTo : class
{
public static readonly Action<object[], TTo> Mapper;

static EntityFillKeyUtilite()
{
Mapper = EntityFillKeyExpressionUtilite<TTo>.Mapper.Compile();
}
}
}
70 changes: 70 additions & 0 deletions Utilites/ExpressionUtilites.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System;
using System.Linq.Expressions;
using System.Reflection;

namespace Common.Utilites
{
/// <summary>
/// Утилиты деревьев выражений
/// </summary>
public static class ExpressionUtilites
{
/// <summary>
/// Получить выражение доступа к свойству объекта
/// </summary>
/// <typeparam name="T">Тип объекта</typeparam>
/// <param name="expression">Выражение</param>
/// <returns>Выражение доступа к свойству объекта</returns>
public static MemberExpression GetMemberExpression<T>(Expression<Func<T, object>> expression)
{
var member = expression.Body as MemberExpression;
if (member != null) return member;
var unary = expression.Body as UnaryExpression;
if (unary == null) return null;
return unary.Operand as MemberExpression;
}

/// <summary>
/// Получить свойство объекта
/// </summary>
/// <typeparam name="T">Тип объекта</typeparam>
/// <param name="expression">Выражение</param>
/// <returns>Свойство объекта</returns>
public static PropertyInfo GetProperty<T>(Expression<Func<T, object>> expression)
{
var memberExpression = GetMemberExpression(expression);
var property = memberExpression.Member as PropertyInfo;
if (property != null) return property;
return null;
}

/// <summary>
/// Получить значение свойства объекта
/// </summary>
/// <typeparam name="T">Тип объекта</typeparam>
/// <param name="expression">Выражение</param>
/// <param name="obj">Объект</param>
/// <returns>Значение свойства объекта</returns>
public static object GetValue<T>(Expression<Func<T, object>> expression, T obj)
{
var property = GetProperty(expression);
if (property == null) return null;
var value = property.GetValue(obj);
return value;
}

/// <summary>
/// Изменить значение свойства объекта
/// </summary>
/// <typeparam name="T">Тип объекта</typeparam>
/// <param name="expression">Выражение</param>
/// <param name="obj">Объект</param>
/// <param name="value">Новое значение</param>
public static void SetValue<T>(Expression<Func<T, object>> expression, T obj, object value)
{
var property = GetProperty(expression);
if (property == null) return;
property.SetValue(obj, value, null);
}
}
}

0 comments on commit 388f214

Please sign in to comment.