Renamed TPrimaryKey to TKey and documented entities.

pull/194/head
Halil İbrahim Kalkan 8 years ago
parent 0e42600639
commit 76fb510c3d

@ -0,0 +1,153 @@
## Entities
Entities are one of the core concepts of DDD (Domain Driven Design). Eric Evans describe it as "*An object that is not fundamentally defined by its attributes, but rather by a thread of continuity and identity*".
An entity is generally mapped to a table in a relational database.
### Entity Class
Entities are derived from `Entity<TKey>` class as shown below:
```C#
public class Person : Entity<int>
{
public string Name { get; set; }
public DateTime CreationTime { get; set; }
public Person()
{
CreationTime = DateTime.Now;
}
}
```
> If you do not want derive your entity from the base `Entity<TKey>` class, you can directly implement `IEntity<TKey>` interface.
`Entity<TKey>` class just defines an `Id` property with the given primary **key type**, which is `int` in the sample above. It can be other types like `string`, `Guid`, `long` or whatever you need.
Entity class also overrides the **equality** operator (==) to easily check if two entities are equal (they are equals if they are same entity type and their Ids are equals).
#### Entities with Composite Keys
Some entities may need to have **composite keys**. In that case, you can derive your entity from the non-generic `Entity` class. Example:
````C#
public class UserRole : Entity
{
public Guid UserId { get; set; }
public Guid RoleId { get; set; }
public DateTime CreationTime { get; set; }
public Phone()
{
}
}
````
For the example above, the composite key is composed of `UserId` and `RoleId`. For a relational database, it is the composite primary key of the related table.
> Composite primary keys has some restriction with repositories. Since it has not known Id property, you can not use `IRepository<TEntity, TKey>` for these entities. However, you can always use `IRepository<TEntity>`. See repository documentation (TODO: link) for more.
### AggregateRoot Class
"*Aggregate is a pattern in Domain-Driven Design. A DDD aggregate is a cluster of domain objects that can be treated as a single unit. An example may be an order and its line-items, these will be separate objects, but it's useful to treat the order (together with its line items) as a single aggregate.*" (see the [full description](http://martinfowler.com/bliki/DDD_Aggregate.html))
`AggregateRoot` extends `Entity`. So, it also has an `Id` property by default.
> Notice that ABP creates default repositories only for aggregate roots by default. However, it's possible to include all entities. See repository documentation (TODO: link) for more.
ABP does not force you to use aggregate roots, you can only use the `Entity` class as defined before. However, if you want to implement DDD and want to create aggregate root classes, there are some best practices you can consider:
* An aggregate root is responsible to preserve it's own integrity. This is also true for all entities, but aggregate root has responsibility for it's sub entities too.
* An aggregate root can be referenced by it's Id. Do not reference it by navigation property.
* An aggregate root is treated as a single unit. It's retrieved and updated as a single unit. It's generally considered as a transaction boundary.
* Work with sub-entities over the aggregate root, do not modify them independently.
#### Aggregate Example
This is a full sample of an aggregate root with a related sub-entity collection:
````C#
public class Order : AggregateRoot<Guid>
{
public virtual string ReferenceNo { get; protected set; }
public virtual int TotalItemCount { get; protected set; }
public virtual DateTime CreationTime { get; protected set; }
public virtual List<OrderLine> OrderLines { get; protected set; }
protected Order()
{
}
public Order(Guid id, string referenceNo)
{
Id = id;
ReferenceNo = referenceNo;
OrderLines = new List<OrderLine>();
}
public void AddProduct(Guid productId, int count)
{
if (count <= 0)
{
throw new ArgumentException(
"You can not add zero or negative count of products!",
nameof(count)
);
}
var existingLine = OrderLines.FirstOrDefault(ol => ol.ProductId == productId);
if (existingLine == null)
{
OrderLines.Add(new OrderLine(this.Id, productId, count));
}
else
{
existingLine.ChangeCount(existingLine.Count + count);
}
TotalItemCount += count;
}
}
public class OrderLine : Entity
{
public virtual Guid OrderId { get; protected set; }
public virtual Guid ProductId { get; protected set; }
public virtual int Count { get; protected set; }
protected OrderLine()
{
}
internal OrderLine(Guid orderId, Guid productId, int count)
{
OrderId = orderId;
ProductId = productId;
Count = count;
}
internal void ChangeCount(int newCount)
{
Count = newCount;
}
}
````
In this example;
* `Order` is an **aggregate root entity** with `Guid` type `Id` property. It has a collection of `OrderLine` entities. `OrderLine` is another entity with a composite primary key (`OrderLine` and ` ProductId`).
* ...

@ -31,14 +31,14 @@ namespace Microsoft.Extensions.DependencyInjection
if (primaryKeyType != null)
{
//IRepository<TEntity, TPrimaryKey>
//IRepository<TEntity, TKey>
var repositoryInterface = typeof(IRepository<,>).MakeGenericType(entityType, primaryKeyType);
if (repositoryInterface.GetTypeInfo().IsAssignableFrom(repositoryImplementationType))
{
services.TryAddTransient(repositoryInterface, repositoryImplementationType);
}
//IQueryableRepository<TEntity, TPrimaryKey>
//IQueryableRepository<TEntity, TKey>
var queryableRepositoryInterface = typeof(IQueryableRepository<,>).MakeGenericType(entityType, primaryKeyType);
if (queryableRepositoryInterface.GetTypeInfo().IsAssignableFrom(repositoryImplementationType))
{

@ -8,15 +8,15 @@ namespace Volo.Abp.Application.Dtos
}
}
public class EntityDto<TPrimaryKey> : EntityDto, IEntityDto<TPrimaryKey>
public class EntityDto<TKey> : EntityDto, IEntityDto<TKey>
{
/// <summary>
/// Id of the entity.
/// </summary>
public TPrimaryKey Id { get; set; }
public TKey Id { get; set; }
/// <summary>
/// Creates a new <see cref="EntityDto{TPrimaryKey}"/> object.
/// Creates a new <see cref="EntityDto{TKey}"/> object.
/// </summary>
public EntityDto()
{
@ -24,10 +24,10 @@ namespace Volo.Abp.Application.Dtos
}
/// <summary>
/// Creates a new <see cref="EntityDto{TPrimaryKey}"/> object.
/// Creates a new <see cref="EntityDto{TKey}"/> object.
/// </summary>
/// <param name="id">Id of the entity</param>
public EntityDto(TPrimaryKey id)
public EntityDto(TKey id)
{
Id = id;
}

@ -5,8 +5,8 @@
}
public interface IEntityDto<TPrimaryKey> : IEntityDto
public interface IEntityDto<TKey> : IEntityDto
{
TPrimaryKey Id { get; set; }
TKey Id { get; set; }
}
}

@ -7,59 +7,59 @@ using Volo.Abp.Linq;
namespace Volo.Abp.Application.Services
{
public abstract class AsyncCrudAppService<TEntity, TEntityDto, TPrimaryKey>
: AsyncCrudAppService<TEntity, TEntityDto, TPrimaryKey, PagedAndSortedResultRequestDto>
where TEntity : class, IEntity<TPrimaryKey>
where TEntityDto : IEntityDto<TPrimaryKey>
public abstract class AsyncCrudAppService<TEntity, TEntityDto, TKey>
: AsyncCrudAppService<TEntity, TEntityDto, TKey, PagedAndSortedResultRequestDto>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected AsyncCrudAppService(IQueryableRepository<TEntity, TPrimaryKey> repository)
protected AsyncCrudAppService(IQueryableRepository<TEntity, TKey> repository)
: base(repository)
{
}
}
public abstract class AsyncCrudAppService<TEntity, TEntityDto, TPrimaryKey, TGetAllInput>
: AsyncCrudAppService<TEntity, TEntityDto, TPrimaryKey, TGetAllInput, TEntityDto, TEntityDto>
where TEntity : class, IEntity<TPrimaryKey>
where TEntityDto : IEntityDto<TPrimaryKey>
public abstract class AsyncCrudAppService<TEntity, TEntityDto, TKey, TGetAllInput>
: AsyncCrudAppService<TEntity, TEntityDto, TKey, TGetAllInput, TEntityDto, TEntityDto>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected AsyncCrudAppService(IQueryableRepository<TEntity, TPrimaryKey> repository)
protected AsyncCrudAppService(IQueryableRepository<TEntity, TKey> repository)
: base(repository)
{
}
}
public abstract class AsyncCrudAppService<TEntity, TEntityDto, TPrimaryKey, TGetAllInput, TCreateInput>
: AsyncCrudAppService<TEntity, TEntityDto, TPrimaryKey, TGetAllInput, TCreateInput, TCreateInput>
public abstract class AsyncCrudAppService<TEntity, TEntityDto, TKey, TGetAllInput, TCreateInput>
: AsyncCrudAppService<TEntity, TEntityDto, TKey, TGetAllInput, TCreateInput, TCreateInput>
where TGetAllInput : IPagedAndSortedResultRequest
where TEntity : class, IEntity<TPrimaryKey>
where TEntityDto : IEntityDto<TPrimaryKey>
where TCreateInput : IEntityDto<TPrimaryKey>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
where TCreateInput : IEntityDto<TKey>
{
protected AsyncCrudAppService(IQueryableRepository<TEntity, TPrimaryKey> repository)
protected AsyncCrudAppService(IQueryableRepository<TEntity, TKey> repository)
: base(repository)
{
}
}
public abstract class AsyncCrudAppService<TEntity, TEntityDto, TPrimaryKey, TGetAllInput, TCreateInput, TUpdateInput>
: CrudAppServiceBase<TEntity, TEntityDto, TPrimaryKey, TGetAllInput, TCreateInput, TUpdateInput>,
IAsyncCrudAppService<TEntityDto, TPrimaryKey, TGetAllInput, TCreateInput, TUpdateInput>
where TEntity : class, IEntity<TPrimaryKey>
where TEntityDto : IEntityDto<TPrimaryKey>
public abstract class AsyncCrudAppService<TEntity, TEntityDto, TKey, TGetAllInput, TCreateInput, TUpdateInput>
: CrudAppServiceBase<TEntity, TEntityDto, TKey, TGetAllInput, TCreateInput, TUpdateInput>,
IAsyncCrudAppService<TEntityDto, TKey, TGetAllInput, TCreateInput, TUpdateInput>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
public IAsyncQueryableExecuter AsyncQueryableExecuter { get; set; }
protected AsyncCrudAppService(IQueryableRepository<TEntity, TPrimaryKey> repository)
protected AsyncCrudAppService(IQueryableRepository<TEntity, TKey> repository)
:base(repository)
{
AsyncQueryableExecuter = DefaultAsyncQueryableExecuter.Instance;
}
public virtual async Task<TEntityDto> GetAsync(TPrimaryKey id)
public virtual async Task<TEntityDto> GetAsync(TKey id)
{
CheckGetPermission();
@ -98,7 +98,7 @@ namespace Volo.Abp.Application.Services
return MapToEntityDto(entity);
}
public virtual async Task<TEntityDto> UpdateAsync(TPrimaryKey id, TUpdateInput input)
public virtual async Task<TEntityDto> UpdateAsync(TKey id, TUpdateInput input)
{
CheckUpdatePermission();
@ -112,14 +112,14 @@ namespace Volo.Abp.Application.Services
return MapToEntityDto(entity);
}
public virtual Task DeleteAsync(TPrimaryKey id)
public virtual Task DeleteAsync(TKey id)
{
CheckDeletePermission();
return Repository.DeleteAsync(id);
}
protected virtual Task<TEntity> GetEntityByIdAsync(TPrimaryKey id)
protected virtual Task<TEntity> GetEntityByIdAsync(TKey id)
{
return Repository.GetAsync(id);
}

@ -5,56 +5,56 @@ using Volo.Abp.Domain.Repositories;
namespace Volo.Abp.Application.Services
{
public abstract class CrudAppService<TEntity, TEntityDto, TPrimaryKey>
: CrudAppService<TEntity, TEntityDto, TPrimaryKey, PagedAndSortedResultRequestDto>
where TEntity : class, IEntity<TPrimaryKey>
where TEntityDto : IEntityDto<TPrimaryKey>
public abstract class CrudAppService<TEntity, TEntityDto, TKey>
: CrudAppService<TEntity, TEntityDto, TKey, PagedAndSortedResultRequestDto>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected CrudAppService(IQueryableRepository<TEntity, TPrimaryKey> repository)
protected CrudAppService(IQueryableRepository<TEntity, TKey> repository)
: base(repository)
{
}
}
public abstract class CrudAppService<TEntity, TEntityDto, TPrimaryKey, TGetAllInput>
: CrudAppService<TEntity, TEntityDto, TPrimaryKey, TGetAllInput, TEntityDto, TEntityDto>
where TEntity : class, IEntity<TPrimaryKey>
where TEntityDto : IEntityDto<TPrimaryKey>
public abstract class CrudAppService<TEntity, TEntityDto, TKey, TGetAllInput>
: CrudAppService<TEntity, TEntityDto, TKey, TGetAllInput, TEntityDto, TEntityDto>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected CrudAppService(IQueryableRepository<TEntity, TPrimaryKey> repository)
protected CrudAppService(IQueryableRepository<TEntity, TKey> repository)
: base(repository)
{
}
}
public abstract class CrudAppService<TEntity, TEntityDto, TPrimaryKey, TGetAllInput, TCreateInput>
: CrudAppService<TEntity, TEntityDto, TPrimaryKey, TGetAllInput, TCreateInput, TCreateInput>
where TEntity : class, IEntity<TPrimaryKey>
where TEntityDto : IEntityDto<TPrimaryKey>
where TCreateInput : IEntityDto<TPrimaryKey>
public abstract class CrudAppService<TEntity, TEntityDto, TKey, TGetAllInput, TCreateInput>
: CrudAppService<TEntity, TEntityDto, TKey, TGetAllInput, TCreateInput, TCreateInput>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
where TCreateInput : IEntityDto<TKey>
{
protected CrudAppService(IQueryableRepository<TEntity, TPrimaryKey> repository)
protected CrudAppService(IQueryableRepository<TEntity, TKey> repository)
: base(repository)
{
}
}
public abstract class CrudAppService<TEntity, TEntityDto, TPrimaryKey, TGetAllInput, TCreateInput, TUpdateInput>
: CrudAppServiceBase<TEntity, TEntityDto, TPrimaryKey, TGetAllInput, TCreateInput, TUpdateInput>,
ICrudAppService<TEntityDto, TPrimaryKey, TGetAllInput, TCreateInput, TUpdateInput>
where TEntity : class, IEntity<TPrimaryKey>
where TEntityDto : IEntityDto<TPrimaryKey>
public abstract class CrudAppService<TEntity, TEntityDto, TKey, TGetAllInput, TCreateInput, TUpdateInput>
: CrudAppServiceBase<TEntity, TEntityDto, TKey, TGetAllInput, TCreateInput, TUpdateInput>,
ICrudAppService<TEntityDto, TKey, TGetAllInput, TCreateInput, TUpdateInput>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected CrudAppService(IQueryableRepository<TEntity, TPrimaryKey> repository)
protected CrudAppService(IQueryableRepository<TEntity, TKey> repository)
: base(repository)
{
}
public virtual TEntityDto Get(TPrimaryKey id)
public virtual TEntityDto Get(TKey id)
{
CheckGetPermission();
@ -93,7 +93,7 @@ namespace Volo.Abp.Application.Services
return MapToEntityDto(entity);
}
public virtual TEntityDto Update(TPrimaryKey id, TUpdateInput input)
public virtual TEntityDto Update(TKey id, TUpdateInput input)
{
CheckUpdatePermission();
@ -105,14 +105,14 @@ namespace Volo.Abp.Application.Services
return MapToEntityDto(entity);
}
public virtual void Delete(TPrimaryKey id)
public virtual void Delete(TKey id)
{
CheckDeletePermission();
Repository.Delete(id);
}
protected virtual TEntity GetEntityById(TPrimaryKey id)
protected virtual TEntity GetEntityById(TKey id)
{
return Repository.Get(id);
}

@ -11,11 +11,11 @@ namespace Volo.Abp.Application.Services
/// This is a common base class for CrudAppService and AsyncCrudAppService classes.
/// Inherit either from CrudAppService or AsyncCrudAppService, not from this class.
/// </summary>
public abstract class CrudAppServiceBase<TEntity, TEntityDto, TPrimaryKey, TGetAllInput, TCreateInput, TUpdateInput> : ApplicationService
where TEntity : class, IEntity<TPrimaryKey>
where TEntityDto : IEntityDto<TPrimaryKey>
public abstract class CrudAppServiceBase<TEntity, TEntityDto, TKey, TGetAllInput, TCreateInput, TUpdateInput> : ApplicationService
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected IQueryableRepository<TEntity, TPrimaryKey> Repository { get; }
protected IQueryableRepository<TEntity, TKey> Repository { get; }
protected virtual string GetPermissionName { get; set; }
@ -27,7 +27,7 @@ namespace Volo.Abp.Application.Services
protected virtual string DeletePermissionName { get; set; }
protected CrudAppServiceBase(IQueryableRepository<TEntity, TPrimaryKey> repository)
protected CrudAppServiceBase(IQueryableRepository<TEntity, TKey> repository)
{
Repository = repository;
}
@ -119,7 +119,7 @@ namespace Volo.Abp.Application.Services
}
/// <summary>
/// Sets Id value for the entity if <see cref="TPrimaryKey"/> is <see cref="Guid"/>.
/// Sets Id value for the entity if <see cref="TKey"/> is <see cref="Guid"/>.
/// It's used while creating a new entity.
/// </summary>
protected virtual void SetIdForGuids(TEntity entity)

@ -3,39 +3,39 @@ using Volo.Abp.Application.Dtos;
namespace Volo.Abp.Application.Services
{
public interface IAsyncCrudAppService<TEntityDto, in TPrimaryKey>
: IAsyncCrudAppService<TEntityDto, TPrimaryKey, PagedAndSortedResultRequestDto>
where TEntityDto : IEntityDto<TPrimaryKey>
public interface IAsyncCrudAppService<TEntityDto, in TKey>
: IAsyncCrudAppService<TEntityDto, TKey, PagedAndSortedResultRequestDto>
where TEntityDto : IEntityDto<TKey>
{
}
public interface IAsyncCrudAppService<TEntityDto, in TPrimaryKey, in TGetListInput>
: IAsyncCrudAppService<TEntityDto, TPrimaryKey, TGetListInput, TEntityDto, TEntityDto>
where TEntityDto : IEntityDto<TPrimaryKey>
public interface IAsyncCrudAppService<TEntityDto, in TKey, in TGetListInput>
: IAsyncCrudAppService<TEntityDto, TKey, TGetListInput, TEntityDto, TEntityDto>
where TEntityDto : IEntityDto<TKey>
{
}
public interface IAsyncCrudAppService<TEntityDto, in TPrimaryKey, in TGetListInput, in TCreateInput>
: IAsyncCrudAppService<TEntityDto, TPrimaryKey, TGetListInput, TCreateInput, TCreateInput>
where TEntityDto : IEntityDto<TPrimaryKey>
public interface IAsyncCrudAppService<TEntityDto, in TKey, in TGetListInput, in TCreateInput>
: IAsyncCrudAppService<TEntityDto, TKey, TGetListInput, TCreateInput, TCreateInput>
where TEntityDto : IEntityDto<TKey>
{
}
public interface IAsyncCrudAppService<TEntityDto, in TPrimaryKey, in TGetListInput, in TCreateInput, in TUpdateInput>
public interface IAsyncCrudAppService<TEntityDto, in TKey, in TGetListInput, in TCreateInput, in TUpdateInput>
: IApplicationService
where TEntityDto : IEntityDto<TPrimaryKey>
where TEntityDto : IEntityDto<TKey>
{
Task<TEntityDto> GetAsync(TPrimaryKey id);
Task<TEntityDto> GetAsync(TKey id);
Task<PagedResultDto<TEntityDto>> GetListAsync(TGetListInput input);
Task<TEntityDto> CreateAsync(TCreateInput input);
Task<TEntityDto> UpdateAsync(TPrimaryKey id, TUpdateInput input);
Task<TEntityDto> UpdateAsync(TKey id, TUpdateInput input);
Task DeleteAsync(TPrimaryKey id);
Task DeleteAsync(TKey id);
}
}

@ -2,39 +2,39 @@ using Volo.Abp.Application.Dtos;
namespace Volo.Abp.Application.Services
{
public interface ICrudAppService<TEntityDto, in TPrimaryKey>
: ICrudAppService<TEntityDto, TPrimaryKey, PagedAndSortedResultRequestDto>
where TEntityDto : IEntityDto<TPrimaryKey>
public interface ICrudAppService<TEntityDto, in TKey>
: ICrudAppService<TEntityDto, TKey, PagedAndSortedResultRequestDto>
where TEntityDto : IEntityDto<TKey>
{
}
public interface ICrudAppService<TEntityDto, in TPrimaryKey, in TGetListInput>
: ICrudAppService<TEntityDto, TPrimaryKey, TGetListInput, TEntityDto, TEntityDto>
where TEntityDto : IEntityDto<TPrimaryKey>
public interface ICrudAppService<TEntityDto, in TKey, in TGetListInput>
: ICrudAppService<TEntityDto, TKey, TGetListInput, TEntityDto, TEntityDto>
where TEntityDto : IEntityDto<TKey>
{
}
public interface ICrudAppService<TEntityDto, in TPrimaryKey, in TGetListInput, in TCreateInput>
: ICrudAppService<TEntityDto, TPrimaryKey, TGetListInput, TCreateInput, TCreateInput>
where TEntityDto : IEntityDto<TPrimaryKey>
public interface ICrudAppService<TEntityDto, in TKey, in TGetListInput, in TCreateInput>
: ICrudAppService<TEntityDto, TKey, TGetListInput, TCreateInput, TCreateInput>
where TEntityDto : IEntityDto<TKey>
{
}
public interface ICrudAppService<TEntityDto, in TPrimaryKey, in TGetListInput, in TCreateInput, in TUpdateInput>
public interface ICrudAppService<TEntityDto, in TKey, in TGetListInput, in TCreateInput, in TUpdateInput>
: IApplicationService
where TEntityDto : IEntityDto<TPrimaryKey>
where TEntityDto : IEntityDto<TKey>
{
TEntityDto Get(TPrimaryKey id);
TEntityDto Get(TKey id);
PagedResultDto<TEntityDto> GetAll(TGetListInput input);
TEntityDto Create(TCreateInput input);
TEntityDto Update(TPrimaryKey id, TUpdateInput input);
TEntityDto Update(TKey id, TUpdateInput input);
void Delete(TPrimaryKey id);
void Delete(TKey id);
}
}

@ -19,7 +19,7 @@ namespace Volo.Abp.DependencyInjection
public Type DefaultRepositoryImplementationType { get; private set; }
public Type DefaultRepositoryImplementationTypeWithoutPrimaryKey { get; private set; }
public Type DefaultRepositoryImplementationTypeWithouTKey { get; private set; }
public bool RegisterDefaultRepositories { get; private set; }
@ -27,7 +27,7 @@ namespace Volo.Abp.DependencyInjection
public Dictionary<Type, Type> CustomRepositories { get; }
public bool SpecifiedDefaultRepositoryTypes => DefaultRepositoryImplementationType != null && DefaultRepositoryImplementationTypeWithoutPrimaryKey != null;
public bool SpecifiedDefaultRepositoryTypes => DefaultRepositoryImplementationType != null && DefaultRepositoryImplementationTypeWithouTKey != null;
protected CommonDbContextRegistrationOptions(Type originalDbContextType)
{
@ -88,14 +88,14 @@ namespace Volo.Abp.DependencyInjection
public ICommonDbContextRegistrationOptionsBuilder SetDefaultRepositoryClasses(
Type repositoryImplementationType,
Type repositoryImplementationTypeWithoutPrimaryKey
Type repositoryImplementationTypeWithouTKey
)
{
Check.NotNull(repositoryImplementationType, nameof(repositoryImplementationType));
Check.NotNull(repositoryImplementationTypeWithoutPrimaryKey, nameof(repositoryImplementationTypeWithoutPrimaryKey));
Check.NotNull(repositoryImplementationTypeWithouTKey, nameof(repositoryImplementationTypeWithouTKey));
DefaultRepositoryImplementationType = repositoryImplementationType;
DefaultRepositoryImplementationTypeWithoutPrimaryKey = repositoryImplementationTypeWithoutPrimaryKey;
DefaultRepositoryImplementationTypeWithouTKey = repositoryImplementationTypeWithouTKey;
return this;
}

@ -48,9 +48,9 @@ namespace Volo.Abp.DependencyInjection
/// Uses given class(es) for default repositories.
/// </summary>
/// <param name="repositoryImplementationType">Repository implementation type</param>
/// <param name="repositoryImplementationTypeWithoutPrimaryKey">Repository implementation type (without primary key)</param>
/// <param name="repositoryImplementationTypeWithouTKey">Repository implementation type (without primary key)</param>
/// <returns></returns>
ICommonDbContextRegistrationOptionsBuilder SetDefaultRepositoryClasses([NotNull] Type repositoryImplementationType, [NotNull] Type repositoryImplementationTypeWithoutPrimaryKey);
ICommonDbContextRegistrationOptionsBuilder SetDefaultRepositoryClasses([NotNull] Type repositoryImplementationType, [NotNull] Type repositoryImplementationTypeWithouTKey);
/// <summary>
/// Replaces given DbContext type with this DbContext type.

@ -7,8 +7,8 @@
}
/// <inheritdoc cref="IAggregateRoot{TPrimaryKey}" />
public abstract class AggregateRoot<TPrimaryKey> : Entity<TPrimaryKey>, IAggregateRoot<TPrimaryKey>
/// <inheritdoc cref="IAggregateRoot{TKey}" />
public abstract class AggregateRoot<TKey> : Entity<TKey>, IAggregateRoot<TKey>
{
}

@ -12,16 +12,16 @@ namespace Volo.Abp.Domain.Entities
}
}
/// <inheritdoc cref="IEntity{TPrimaryKey}" />
public abstract class Entity<TPrimaryKey> : Entity, IEntity<TPrimaryKey>
/// <inheritdoc cref="IEntity{TKey}" />
public abstract class Entity<TKey> : Entity, IEntity<TKey>
{
/// <inheritdoc/>
public virtual TPrimaryKey Id { get; set; }
public virtual TKey Id { get; set; }
/// <inheritdoc/>
public override bool Equals(object obj)
{
if (obj == null || !(obj is Entity<TPrimaryKey>))
if (obj == null || !(obj is Entity<TKey>))
{
return false;
}
@ -33,7 +33,7 @@ namespace Volo.Abp.Domain.Entities
}
//Transient objects are not considered as equal
var other = (Entity<TPrimaryKey>)obj;
var other = (Entity<TKey>)obj;
if (EntityHelper.IsTransient(this) && EntityHelper.IsTransient(other))
{
return false;
@ -61,7 +61,7 @@ namespace Volo.Abp.Domain.Entities
return Id.GetHashCode();
}
public static bool operator ==(Entity<TPrimaryKey> left, Entity<TPrimaryKey> right)
public static bool operator ==(Entity<TKey> left, Entity<TKey> right)
{
if (Equals(left, null))
{
@ -71,7 +71,7 @@ namespace Volo.Abp.Domain.Entities
return left.Equals(right);
}
public static bool operator !=(Entity<TPrimaryKey> left, Entity<TPrimaryKey> right)
public static bool operator !=(Entity<TKey> left, Entity<TKey> right)
{
return !(left == right);
}

@ -16,20 +16,20 @@ namespace Volo.Abp.Domain.Entities
return typeof(IEntity).IsAssignableFrom(type);
}
public static bool IsTransient<TPrimaryKey>(IEntity<TPrimaryKey> entity) // TODO: Completely remove IsTransient
public static bool IsTransient<TKey>(IEntity<TKey> entity) // TODO: Completely remove IsTransient
{
if (EqualityComparer<TPrimaryKey>.Default.Equals(entity.Id, default))
if (EqualityComparer<TKey>.Default.Equals(entity.Id, default))
{
return true;
}
//Workaround for EF Core since it sets int/long to min value when attaching to dbcontext
if (typeof(TPrimaryKey) == typeof(int))
if (typeof(TKey) == typeof(int))
{
return Convert.ToInt32(entity.Id) <= 0;
}
if (typeof(TPrimaryKey) == typeof(long))
if (typeof(TKey) == typeof(long))
{
return Convert.ToInt64(entity.Id) <= 0;
}
@ -39,7 +39,7 @@ namespace Volo.Abp.Domain.Entities
/// <summary>
/// Tries to find the primary key type of the given entity type.
/// May return null if given type does not implement <see cref="IEntity{TPrimaryKey}"/>
/// May return null if given type does not implement <see cref="IEntity{TKey}"/>
/// </summary>
[CanBeNull]
public static Type FindPrimaryKeyType<TEntity>()
@ -50,7 +50,7 @@ namespace Volo.Abp.Domain.Entities
/// <summary>
/// Tries to find the primary key type of the given entity type.
/// May return null if given type does not implement <see cref="IEntity{TPrimaryKey}"/>
/// May return null if given type does not implement <see cref="IEntity{TKey}"/>
/// </summary>
[CanBeNull]
public static Type FindPrimaryKeyType([NotNull] Type entityType)
@ -71,13 +71,13 @@ namespace Volo.Abp.Domain.Entities
return null;
}
public static Expression<Func<TEntity, bool>> CreateEqualityExpressionForId<TEntity, TPrimaryKey>(TPrimaryKey id)
where TEntity : IEntity<TPrimaryKey>
public static Expression<Func<TEntity, bool>> CreateEqualityExpressionForId<TEntity, TKey>(TKey id)
where TEntity : IEntity<TKey>
{
var lambdaParam = Expression.Parameter(typeof(TEntity));
var lambdaBody = Expression.Equal(
Expression.PropertyOrField(lambdaParam, "Id"),
Expression.Constant(id, typeof(TPrimaryKey))
Expression.Constant(id, typeof(TKey))
);
return Expression.Lambda<Func<TEntity, bool>>(lambdaBody, lambdaParam);

@ -2,7 +2,7 @@
{
/// <summary>
/// Defines an aggregate root. It's primary key may not be "Id" or it may have a composite primary key.
/// Use <see cref="IAggregateRoot{TPrimaryKey}"/> where possible for better integration to repositories and other structures in the framework.
/// Use <see cref="IAggregateRoot{TKey}"/> where possible for better integration to repositories and other structures in the framework.
/// </summary>
public interface IAggregateRoot : IEntity
{
@ -12,8 +12,8 @@
/// <summary>
/// Defines an aggregate root with a single primary key with "Id" property.
/// </summary>
/// <typeparam name="TPrimaryKey">Type of the primary key of the entity</typeparam>
public interface IAggregateRoot<TPrimaryKey> : IEntity<TPrimaryKey>, IAggregateRoot
/// <typeparam name="TKey">Type of the primary key of the entity</typeparam>
public interface IAggregateRoot<TKey> : IEntity<TKey>, IAggregateRoot
{
}

@ -2,7 +2,7 @@
{
/// <summary>
/// Defines an entity. It's primary key may not be "Id" or it mah have a composite primary key.
/// Use <see cref="IEntity{TPrimaryKey}"/> where possible for better integration to repositories and other structures in the framework.
/// Use <see cref="IEntity{TKey}"/> where possible for better integration to repositories and other structures in the framework.
/// </summary>
public interface IEntity
{
@ -12,12 +12,12 @@
/// <summary>
/// Defines an entity with a single primary key with "Id" property.
/// </summary>
/// <typeparam name="TPrimaryKey">Type of the primary key of the entity</typeparam>
public interface IEntity<TPrimaryKey> : IEntity
/// <typeparam name="TKey">Type of the primary key of the entity</typeparam>
public interface IEntity<TKey> : IEntity
{
/// <summary>
/// Unique identifier for this entity.
/// </summary>
TPrimaryKey Id { get; set; }
TKey Id { get; set; }
}
}

@ -31,8 +31,8 @@ namespace Volo.Abp.Domain.Repositories
Task DeleteAsync([NotNull] Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);
}
public interface IQueryableRepository<TEntity, TPrimaryKey> : IQueryableRepository<TEntity>, IRepository<TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>
public interface IQueryableRepository<TEntity, TKey> : IQueryableRepository<TEntity>, IRepository<TEntity, TKey>
where TEntity : class, IEntity<TKey>
{
}
}

@ -69,8 +69,8 @@ namespace Volo.Abp.Domain.Repositories
Task DeleteAsync([NotNull] TEntity entity, CancellationToken cancellationToken = default); //TODO: Return true if deleted
}
public interface IRepository<TEntity, TPrimaryKey> : IRepository<TEntity>
where TEntity : class, IEntity<TPrimaryKey>
public interface IRepository<TEntity, TKey> : IRepository<TEntity>
where TEntity : class, IEntity<TKey>
{
/// <summary>
/// Gets an entity with given primary key.
@ -79,7 +79,7 @@ namespace Volo.Abp.Domain.Repositories
/// <param name="id">Primary key of the entity to get</param>
/// <returns>Entity</returns>
[NotNull]
TEntity Get(TPrimaryKey id);
TEntity Get(TKey id);
/// <summary>
/// Gets an entity with given primary key.
@ -89,7 +89,7 @@ namespace Volo.Abp.Domain.Repositories
/// <param name="cancellationToken">A <see cref="T:System.Threading.CancellationToken" /> to observe while waiting for the task to complete.</param>
/// <returns>Entity</returns>
[NotNull]
Task<TEntity> GetAsync(TPrimaryKey id, CancellationToken cancellationToken = default);
Task<TEntity> GetAsync(TKey id, CancellationToken cancellationToken = default);
/// <summary>
/// Gets an entity with given primary key or null if not found.
@ -97,7 +97,7 @@ namespace Volo.Abp.Domain.Repositories
/// <param name="id">Primary key of the entity to get</param>
/// <returns>Entity or null</returns>
[CanBeNull]
TEntity Find(TPrimaryKey id);
TEntity Find(TKey id);
/// <summary>
/// Gets an entity with given primary key or null if not found.
@ -105,19 +105,19 @@ namespace Volo.Abp.Domain.Repositories
/// <param name="id">Primary key of the entity to get</param>
/// <param name="cancellationToken">A <see cref="T:System.Threading.CancellationToken" /> to observe while waiting for the task to complete.</param>
/// <returns>Entity or null</returns>
Task<TEntity> FindAsync(TPrimaryKey id, CancellationToken cancellationToken = default);
Task<TEntity> FindAsync(TKey id, CancellationToken cancellationToken = default);
/// <summary>
/// Deletes an entity by primary key.
/// </summary>
/// <param name="id">Primary key of the entity</param>
void Delete(TPrimaryKey id); //TODO: Return true if deleted
void Delete(TKey id); //TODO: Return true if deleted
/// <summary>
/// Deletes an entity by primary key.
/// </summary>
/// <param name="cancellationToken">A <see cref="T:System.Threading.CancellationToken" /> to observe while waiting for the task to complete.</param>
/// <param name="id">Primary key of the entity</param>
Task DeleteAsync(TPrimaryKey id, CancellationToken cancellationToken = default); //TODO: Return true if deleted
Task DeleteAsync(TKey id, CancellationToken cancellationToken = default); //TODO: Return true if deleted
}
}

@ -7,8 +7,8 @@ using Volo.Abp.Domain.Entities;
namespace Volo.Abp.Domain.Repositories
{
public interface ISupportsExplicitLoading<TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>
public interface ISupportsExplicitLoading<TEntity, TKey>
where TEntity : class, IEntity<TKey>
{
Task EnsureCollectionLoadedAsync<TProperty>(
TEntity entity,

@ -68,15 +68,15 @@ namespace Volo.Abp.Domain.Repositories
}
}
public abstract class QueryableRepositoryBase<TEntity, TPrimaryKey> : QueryableRepositoryBase<TEntity>, IQueryableRepository<TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>
public abstract class QueryableRepositoryBase<TEntity, TKey> : QueryableRepositoryBase<TEntity>, IQueryableRepository<TEntity, TKey>
where TEntity : class, IEntity<TKey>
{
public virtual TEntity Find(TPrimaryKey id)
public virtual TEntity Find(TKey id)
{
return GetQueryable().FirstOrDefault(EntityHelper.CreateEqualityExpressionForId<TEntity, TPrimaryKey>(id));
return GetQueryable().FirstOrDefault(EntityHelper.CreateEqualityExpressionForId<TEntity, TKey>(id));
}
public virtual TEntity Get(TPrimaryKey id)
public virtual TEntity Get(TKey id)
{
var entity = Find(id);
@ -88,17 +88,17 @@ namespace Volo.Abp.Domain.Repositories
return entity;
}
public virtual Task<TEntity> GetAsync(TPrimaryKey id, CancellationToken cancellationToken = default)
public virtual Task<TEntity> GetAsync(TKey id, CancellationToken cancellationToken = default)
{
return Task.FromResult(Get(id));
}
public virtual Task<TEntity> FindAsync(TPrimaryKey id, CancellationToken cancellationToken = default)
public virtual Task<TEntity> FindAsync(TKey id, CancellationToken cancellationToken = default)
{
return Task.FromResult(Find(id));
}
public virtual void Delete(TPrimaryKey id)
public virtual void Delete(TKey id)
{
var entity = Find(id);
if (entity == null)
@ -109,7 +109,7 @@ namespace Volo.Abp.Domain.Repositories
Delete(entity);
}
public virtual Task DeleteAsync(TPrimaryKey id, CancellationToken cancellationToken = default)
public virtual Task DeleteAsync(TKey id, CancellationToken cancellationToken = default)
{
Delete(id);
return Task.CompletedTask;

@ -43,10 +43,10 @@ namespace Volo.Abp.Domain.Repositories
}
}
public abstract class RepositoryBase<TEntity, TPrimaryKey> : RepositoryBase<TEntity>, IRepository<TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>
public abstract class RepositoryBase<TEntity, TKey> : RepositoryBase<TEntity>, IRepository<TEntity, TKey>
where TEntity : class, IEntity<TKey>
{
public virtual TEntity Get(TPrimaryKey id)
public virtual TEntity Get(TKey id)
{
var entity = Find(id);
@ -58,19 +58,19 @@ namespace Volo.Abp.Domain.Repositories
return entity;
}
public virtual Task<TEntity> GetAsync(TPrimaryKey id, CancellationToken cancellationToken = default)
public virtual Task<TEntity> GetAsync(TKey id, CancellationToken cancellationToken = default)
{
return Task.FromResult(Get(id));
}
public abstract TEntity Find(TPrimaryKey id);
public abstract TEntity Find(TKey id);
public virtual Task<TEntity> FindAsync(TPrimaryKey id, CancellationToken cancellationToken = default)
public virtual Task<TEntity> FindAsync(TKey id, CancellationToken cancellationToken = default)
{
return Task.FromResult(Find(id));
}
public virtual void Delete(TPrimaryKey id)
public virtual void Delete(TKey id)
{
var entity = Find(id);
if (entity == null)
@ -81,7 +81,7 @@ namespace Volo.Abp.Domain.Repositories
Delete(entity);
}
public virtual Task DeleteAsync(TPrimaryKey id, CancellationToken cancellationToken = default)
public virtual Task DeleteAsync(TKey id, CancellationToken cancellationToken = default)
{
Delete(id);
return Task.CompletedTask;

@ -11,55 +11,55 @@ namespace Volo.Abp.Domain.Repositories
{
public static class RepositoryExtensions
{
public static async Task EnsureCollectionLoadedAsync<TEntity, TPrimaryKey, TProperty>(
this IRepository<TEntity, TPrimaryKey> repository,
public static async Task EnsureCollectionLoadedAsync<TEntity, TKey, TProperty>(
this IRepository<TEntity, TKey> repository,
TEntity entity,
Expression<Func<TEntity, IEnumerable<TProperty>>> propertyExpression,
CancellationToken cancellationToken = default
)
where TEntity : class, IEntity<TPrimaryKey>
where TEntity : class, IEntity<TKey>
where TProperty : class
{
var repo = ProxyHelper.UnProxy(repository) as ISupportsExplicitLoading<TEntity, TPrimaryKey>;
var repo = ProxyHelper.UnProxy(repository) as ISupportsExplicitLoading<TEntity, TKey>;
if (repo != null)
{
await repo.EnsureCollectionLoadedAsync(entity, propertyExpression, cancellationToken);
}
}
public static void EnsureCollectionLoaded<TEntity, TPrimaryKey, TProperty>(
this IRepository<TEntity, TPrimaryKey> repository,
public static void EnsureCollectionLoaded<TEntity, TKey, TProperty>(
this IRepository<TEntity, TKey> repository,
TEntity entity,
Expression<Func<TEntity, IEnumerable<TProperty>>> propertyExpression
)
where TEntity : class, IEntity<TPrimaryKey>
where TEntity : class, IEntity<TKey>
where TProperty : class
{
AsyncHelper.RunSync(() => repository.EnsureCollectionLoadedAsync(entity, propertyExpression));
}
public static async Task EnsurePropertyLoadedAsync<TEntity, TPrimaryKey, TProperty>(
this IRepository<TEntity, TPrimaryKey> repository,
public static async Task EnsurePropertyLoadedAsync<TEntity, TKey, TProperty>(
this IRepository<TEntity, TKey> repository,
TEntity entity,
Expression<Func<TEntity, TProperty>> propertyExpression,
CancellationToken cancellationToken = default
)
where TEntity : class, IEntity<TPrimaryKey>
where TEntity : class, IEntity<TKey>
where TProperty : class
{
var repo = ProxyHelper.UnProxy(repository) as ISupportsExplicitLoading<TEntity, TPrimaryKey>;
var repo = ProxyHelper.UnProxy(repository) as ISupportsExplicitLoading<TEntity, TKey>;
if (repo != null)
{
await repo.EnsurePropertyLoadedAsync(entity, propertyExpression, cancellationToken);
}
}
public static void EnsurePropertyLoaded<TEntity, TPrimaryKey, TProperty>(
this IRepository<TEntity, TPrimaryKey> repository,
public static void EnsurePropertyLoaded<TEntity, TKey, TProperty>(
this IRepository<TEntity, TKey> repository,
TEntity entity,
Expression<Func<TEntity, TProperty>> propertyExpression
)
where TEntity : class, IEntity<TPrimaryKey>
where TEntity : class, IEntity<TKey>
where TProperty : class
{
AsyncHelper.RunSync(() => repository.EnsurePropertyLoadedAsync(entity, propertyExpression));

@ -57,7 +57,7 @@ namespace Volo.Abp.Domain.Repositories
if (primaryKeyType == null)
{
return Options.SpecifiedDefaultRepositoryTypes
? Options.DefaultRepositoryImplementationTypeWithoutPrimaryKey.MakeGenericType(entityType)
? Options.DefaultRepositoryImplementationTypeWithouTKey.MakeGenericType(entityType)
: GetRepositoryType(Options.DefaultRepositoryDbContextType, entityType);
}

@ -7,25 +7,25 @@ namespace Volo.Abp.Domain.Repositories
{
public static class EfCoreRepositoryExtensions
{
public static DbContext GetDbContext<TEntity, TPrimaryKey>(this IRepository<TEntity, TPrimaryKey> repository)
where TEntity : class, IEntity<TPrimaryKey>
public static DbContext GetDbContext<TEntity, TKey>(this IRepository<TEntity, TKey> repository)
where TEntity : class, IEntity<TKey>
{
return repository.ToEfCoreRepository().DbContext;
}
public static DbSet<TEntity> GetDbSet<TEntity, TPrimaryKey>(this IRepository<TEntity, TPrimaryKey> repository)
where TEntity : class, IEntity<TPrimaryKey>
public static DbSet<TEntity> GetDbSet<TEntity, TKey>(this IRepository<TEntity, TKey> repository)
where TEntity : class, IEntity<TKey>
{
return repository.ToEfCoreRepository().DbSet;
}
public static IEfCoreRepository<TEntity, TPrimaryKey> ToEfCoreRepository<TEntity, TPrimaryKey>(this IRepository<TEntity, TPrimaryKey> repository)
where TEntity : class, IEntity<TPrimaryKey>
public static IEfCoreRepository<TEntity, TKey> ToEfCoreRepository<TEntity, TKey>(this IRepository<TEntity, TKey> repository)
where TEntity : class, IEntity<TKey>
{
var efCoreRepository = repository as IEfCoreRepository<TEntity, TPrimaryKey>;
var efCoreRepository = repository as IEfCoreRepository<TEntity, TKey>;
if (efCoreRepository == null)
{
throw new ArgumentException("Given repository does not implement " + typeof(IEfCoreRepository<TEntity, TPrimaryKey>).AssemblyQualifiedName, nameof(repository));
throw new ArgumentException("Given repository does not implement " + typeof(IEfCoreRepository<TEntity, TKey>).AssemblyQualifiedName, nameof(repository));
}
return efCoreRepository;

@ -95,12 +95,12 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore
}
}
public class EfCoreRepository<TDbContext, TEntity, TPrimaryKey> : EfCoreRepository<TDbContext, TEntity>,
IEfCoreRepository<TEntity, TPrimaryKey>,
ISupportsExplicitLoading<TEntity, TPrimaryKey>
public class EfCoreRepository<TDbContext, TEntity, TKey> : EfCoreRepository<TDbContext, TEntity>,
IEfCoreRepository<TEntity, TKey>,
ISupportsExplicitLoading<TEntity, TKey>
where TDbContext : IEfCoreDbContext
where TEntity : class, IEntity<TPrimaryKey>
where TEntity : class, IEntity<TKey>
{
public EfCoreRepository(IDbContextProvider<TDbContext> dbContextProvider)
: base(dbContextProvider)
@ -108,7 +108,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore
}
public TEntity Get(TPrimaryKey id)
public TEntity Get(TKey id)
{
var entity = Find(id);
@ -120,7 +120,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore
return entity;
}
public virtual async Task<TEntity> GetAsync(TPrimaryKey id, CancellationToken cancellationToken = default)
public virtual async Task<TEntity> GetAsync(TKey id, CancellationToken cancellationToken = default)
{
var entity = await FindAsync(id, GetCancellationToken(cancellationToken));
@ -132,17 +132,17 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore
return entity;
}
public virtual TEntity Find(TPrimaryKey id)
public virtual TEntity Find(TKey id)
{
return DbSet.Find(id);
}
public virtual Task<TEntity> FindAsync(TPrimaryKey id, CancellationToken cancellationToken = default)
public virtual Task<TEntity> FindAsync(TKey id, CancellationToken cancellationToken = default)
{
return DbSet.FindAsync(new object[] { id }, GetCancellationToken(cancellationToken));
}
public virtual void Delete(TPrimaryKey id)
public virtual void Delete(TKey id)
{
var entity = Find(id);
if (entity == null)
@ -153,7 +153,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore
Delete(entity);
}
public virtual Task DeleteAsync(TPrimaryKey id, CancellationToken cancellationToken = default)
public virtual Task DeleteAsync(TKey id, CancellationToken cancellationToken = default)
{
Delete(id);
return Task.CompletedTask;

@ -11,8 +11,8 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore
DbSet<TEntity> DbSet { get; }
}
public interface IEfCoreRepository<TEntity, TPrimaryKey> : IEfCoreRepository<TEntity>, IQueryableRepository<TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>
public interface IEfCoreRepository<TEntity, TKey> : IEfCoreRepository<TEntity>, IQueryableRepository<TEntity, TKey>
where TEntity : class, IEntity<TKey>
{
}

@ -6,6 +6,6 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb
{
List<TEntity> Collection<TEntity>();
TPrimaryKey GenerateNextId<TEntity, TPrimaryKey>();
TKey GenerateNextId<TEntity, TKey>();
}
}

@ -11,8 +11,8 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb
List<TEntity> Collection { get; }
}
public interface IMemoryDbRepository<TEntity, TPrimaryKey> : IMemoryDbRepository<TEntity>, IQueryableRepository<TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>
public interface IMemoryDbRepository<TEntity, TKey> : IMemoryDbRepository<TEntity>, IQueryableRepository<TEntity, TKey>
where TEntity : class, IEntity<TKey>
{
}

@ -8,24 +8,24 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb
private int _lastInt;
private long _lastLong;
public TPrimaryKey GenerateNext<TPrimaryKey>()
public TKey GenerateNext<TKey>()
{
if (typeof(TPrimaryKey) == typeof(Guid))
if (typeof(TKey) == typeof(Guid))
{
return (TPrimaryKey)(object)Guid.NewGuid();
return (TKey)(object)Guid.NewGuid();
}
if (typeof(TPrimaryKey) == typeof(int))
if (typeof(TKey) == typeof(int))
{
return (TPrimaryKey)(object)Interlocked.Increment(ref _lastInt);
return (TKey)(object)Interlocked.Increment(ref _lastInt);
}
if (typeof(TPrimaryKey) == typeof(long))
if (typeof(TKey) == typeof(long))
{
return (TPrimaryKey)(object)Interlocked.Increment(ref _lastLong);
return (TKey)(object)Interlocked.Increment(ref _lastLong);
}
throw new AbpException("Not supported PrimaryKey type: " + typeof(TPrimaryKey).FullName);
throw new AbpException("Not supported PrimaryKey type: " + typeof(TKey).FullName);
}
}
}

@ -21,11 +21,11 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb
return _sets.GetOrAdd(typeof(TEntity), _ => new List<TEntity>()) as List<TEntity>;
}
public TPrimaryKey GenerateNextId<TEntity, TPrimaryKey>()
public TKey GenerateNextId<TEntity, TKey>()
{
return _idGenerators
.GetOrAdd(typeof(TEntity), () => new InMemoryIdGenerator())
.GenerateNext<TPrimaryKey>();
.GenerateNext<TKey>();
}
}
}

@ -45,9 +45,9 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb
}
}
public class MemoryDbRepository<TMemoryDbContext, TEntity, TPrimaryKey> : MemoryDbRepository<TMemoryDbContext, TEntity>, IMemoryDbRepository<TEntity, TPrimaryKey>
public class MemoryDbRepository<TMemoryDbContext, TEntity, TKey> : MemoryDbRepository<TMemoryDbContext, TEntity>, IMemoryDbRepository<TEntity, TKey>
where TMemoryDbContext : MemoryDbContext
where TEntity : class, IEntity<TPrimaryKey>
where TEntity : class, IEntity<TKey>
{
public MemoryDbRepository(IMemoryDatabaseProvider<TMemoryDbContext> databaseProvider)
: base(databaseProvider)
@ -62,21 +62,21 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb
private void SetIdIfNeeded(TEntity entity)
{
if (typeof(TPrimaryKey) == typeof(int) || typeof(TPrimaryKey) == typeof(long) || typeof(TPrimaryKey) == typeof(Guid))
if (typeof(TKey) == typeof(int) || typeof(TKey) == typeof(long) || typeof(TKey) == typeof(Guid))
{
if (EntityHelper.IsTransient(entity))
{
entity.Id = Database.GenerateNextId<TEntity, TPrimaryKey>();
entity.Id = Database.GenerateNextId<TEntity, TKey>();
}
}
}
public virtual TEntity Find(TPrimaryKey id)
public virtual TEntity Find(TKey id)
{
return GetQueryable().FirstOrDefault(EntityHelper.CreateEqualityExpressionForId<TEntity, TPrimaryKey>(id));
return GetQueryable().FirstOrDefault(EntityHelper.CreateEqualityExpressionForId<TEntity, TKey>(id));
}
public virtual TEntity Get(TPrimaryKey id)
public virtual TEntity Get(TKey id)
{
var entity = Find(id);
@ -88,17 +88,17 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb
return entity;
}
public virtual Task<TEntity> GetAsync(TPrimaryKey id, CancellationToken cancellationToken = default)
public virtual Task<TEntity> GetAsync(TKey id, CancellationToken cancellationToken = default)
{
return Task.FromResult(Get(id));
}
public virtual Task<TEntity> FindAsync(TPrimaryKey id, CancellationToken cancellationToken = default)
public virtual Task<TEntity> FindAsync(TKey id, CancellationToken cancellationToken = default)
{
return Task.FromResult(Find(id));
}
public virtual void Delete(TPrimaryKey id)
public virtual void Delete(TKey id)
{
var entity = Find(id);
if (entity == null)
@ -109,7 +109,7 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb
Delete(entity);
}
public virtual Task DeleteAsync(TPrimaryKey id, CancellationToken cancellationToken = default)
public virtual Task DeleteAsync(TKey id, CancellationToken cancellationToken = default)
{
Delete(id);
return Task.CompletedTask;

@ -7,25 +7,25 @@ namespace Volo.Abp.Domain.Repositories
{
public static class MemoryDbCoreRepositoryExtensions
{
public static IMemoryDatabase GetDatabase<TEntity, TPrimaryKey>(this IRepository<TEntity, TPrimaryKey> repository)
where TEntity : class, IEntity<TPrimaryKey>
public static IMemoryDatabase GetDatabase<TEntity, TKey>(this IRepository<TEntity, TKey> repository)
where TEntity : class, IEntity<TKey>
{
return repository.ToMemoryDbRepository().Database;
}
public static List<TEntity> GetCollection<TEntity, TPrimaryKey>(this IRepository<TEntity, TPrimaryKey> repository)
where TEntity : class, IEntity<TPrimaryKey>
public static List<TEntity> GetCollection<TEntity, TKey>(this IRepository<TEntity, TKey> repository)
where TEntity : class, IEntity<TKey>
{
return repository.ToMemoryDbRepository().Collection;
}
public static IMemoryDbRepository<TEntity, TPrimaryKey> ToMemoryDbRepository<TEntity, TPrimaryKey>(this IRepository<TEntity, TPrimaryKey> repository)
where TEntity : class, IEntity<TPrimaryKey>
public static IMemoryDbRepository<TEntity, TKey> ToMemoryDbRepository<TEntity, TKey>(this IRepository<TEntity, TKey> repository)
where TEntity : class, IEntity<TKey>
{
var memoryDbRepository = repository as IMemoryDbRepository<TEntity, TPrimaryKey>;
var memoryDbRepository = repository as IMemoryDbRepository<TEntity, TKey>;
if (memoryDbRepository == null)
{
throw new ArgumentException("Given repository does not implement " + typeof(IMemoryDbRepository<TEntity, TPrimaryKey>).AssemblyQualifiedName, nameof(repository));
throw new ArgumentException("Given repository does not implement " + typeof(IMemoryDbRepository<TEntity, TKey>).AssemblyQualifiedName, nameof(repository));
}
return memoryDbRepository;

@ -13,8 +13,8 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
string CollectionName { get; }
}
public interface IMongoDbRepository<TEntity, TPrimaryKey> : IMongoDbRepository<TEntity>, IQueryableRepository<TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>
public interface IMongoDbRepository<TEntity, TKey> : IMongoDbRepository<TEntity>, IQueryableRepository<TEntity, TKey>
where TEntity : class, IEntity<TKey>
{
}

@ -81,9 +81,9 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
}
}
public class MongoDbRepository<TMongoDbContext, TEntity, TPrimaryKey> : MongoDbRepository<TMongoDbContext, TEntity>, IMongoDbRepository<TEntity, TPrimaryKey>
public class MongoDbRepository<TMongoDbContext, TEntity, TKey> : MongoDbRepository<TMongoDbContext, TEntity>, IMongoDbRepository<TEntity, TKey>
where TMongoDbContext : AbpMongoDbContext
where TEntity : class, IEntity<TPrimaryKey>
where TEntity : class, IEntity<TKey>
{
public MongoDbRepository(IMongoDatabaseProvider<TMongoDbContext> databaseProvider)
: base(databaseProvider)
@ -91,7 +91,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
}
public virtual TEntity Get(TPrimaryKey id)
public virtual TEntity Get(TKey id)
{
var entity = Find(id);
@ -103,7 +103,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
return entity;
}
public virtual async Task<TEntity> GetAsync(TPrimaryKey id, CancellationToken cancellationToken = default)
public virtual async Task<TEntity> GetAsync(TKey id, CancellationToken cancellationToken = default)
{
var entity = await FindAsync(id, cancellationToken);
@ -115,22 +115,22 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
return entity;
}
public virtual void Delete(TPrimaryKey id)
public virtual void Delete(TKey id)
{
Collection.DeleteOne(CreateEntityFilter(id));
}
public virtual Task DeleteAsync(TPrimaryKey id, CancellationToken cancellationToken = default)
public virtual Task DeleteAsync(TKey id, CancellationToken cancellationToken = default)
{
return Collection.DeleteOneAsync(CreateEntityFilter(id), cancellationToken);
}
public virtual async Task<TEntity> FindAsync(TPrimaryKey id, CancellationToken cancellationToken = default)
public virtual async Task<TEntity> FindAsync(TKey id, CancellationToken cancellationToken = default)
{
return await Collection.Find(CreateEntityFilter(id)).FirstOrDefaultAsync(cancellationToken);
}
public virtual TEntity Find(TPrimaryKey id)
public virtual TEntity Find(TKey id)
{
return Collection.Find(CreateEntityFilter(id)).FirstOrDefault();
}
@ -140,7 +140,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
return Builders<TEntity>.Filter.Eq(e => e.Id, entity.Id);
}
private static FilterDefinition<TEntity> CreateEntityFilter(TPrimaryKey id)
private static FilterDefinition<TEntity> CreateEntityFilter(TKey id)
{
return Builders<TEntity>.Filter.Eq(e => e.Id, id);
}

@ -7,31 +7,31 @@ namespace Volo.Abp.Domain.Repositories
{
public static class MongoDbCoreRepositoryExtensions
{
public static IMongoDatabase GetDatabase<TEntity, TPrimaryKey>(this IRepository<TEntity, TPrimaryKey> repository)
where TEntity : class, IEntity<TPrimaryKey>
public static IMongoDatabase GetDatabase<TEntity, TKey>(this IRepository<TEntity, TKey> repository)
where TEntity : class, IEntity<TKey>
{
return repository.ToMongoDbRepository().Database;
}
public static IMongoCollection<TEntity> GetCollection<TEntity, TPrimaryKey>(this IRepository<TEntity, TPrimaryKey> repository)
where TEntity : class, IEntity<TPrimaryKey>
public static IMongoCollection<TEntity> GetCollection<TEntity, TKey>(this IRepository<TEntity, TKey> repository)
where TEntity : class, IEntity<TKey>
{
return repository.ToMongoDbRepository().Collection;
}
public static string GetCollectionName<TEntity, TPrimaryKey>(this IRepository<TEntity, TPrimaryKey> repository)
where TEntity : class, IEntity<TPrimaryKey>
public static string GetCollectionName<TEntity, TKey>(this IRepository<TEntity, TKey> repository)
where TEntity : class, IEntity<TKey>
{
return repository.ToMongoDbRepository().CollectionName;
}
public static IMongoDbRepository<TEntity, TPrimaryKey> ToMongoDbRepository<TEntity, TPrimaryKey>(this IRepository<TEntity, TPrimaryKey> repository)
where TEntity : class, IEntity<TPrimaryKey>
public static IMongoDbRepository<TEntity, TKey> ToMongoDbRepository<TEntity, TKey>(this IRepository<TEntity, TKey> repository)
where TEntity : class, IEntity<TKey>
{
var mongoDbRepository = repository as IMongoDbRepository<TEntity, TPrimaryKey>;
var mongoDbRepository = repository as IMongoDbRepository<TEntity, TKey>;
if (mongoDbRepository == null)
{
throw new ArgumentException("Given repository does not implement " + typeof(IMongoDbRepository<TEntity, TPrimaryKey>).AssemblyQualifiedName, nameof(repository));
throw new ArgumentException("Given repository does not implement " + typeof(IMongoDbRepository<TEntity, TKey>).AssemblyQualifiedName, nameof(repository));
}
return mongoDbRepository;

@ -169,35 +169,35 @@ namespace Volo.Abp.Domain.Repositories
}
}
public class MyTestDefaultRepository<TEntity, TPrimaryKey> : MyTestDefaultRepository<TEntity>, IRepository<TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>
public class MyTestDefaultRepository<TEntity, TKey> : MyTestDefaultRepository<TEntity>, IRepository<TEntity, TKey>
where TEntity : class, IEntity<TKey>
{
public TEntity Get(TPrimaryKey id)
public TEntity Get(TKey id)
{
throw new NotImplementedException();
}
public Task<TEntity> GetAsync(TPrimaryKey id, CancellationToken cancellationToken = default)
public Task<TEntity> GetAsync(TKey id, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public TEntity Find(TPrimaryKey id)
public TEntity Find(TKey id)
{
throw new NotImplementedException();
}
public Task<TEntity> FindAsync(TPrimaryKey id, CancellationToken cancellationToken = default)
public Task<TEntity> FindAsync(TKey id, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public void Delete(TPrimaryKey id)
public void Delete(TKey id)
{
throw new NotImplementedException();
}
public Task DeleteAsync(TPrimaryKey id, CancellationToken cancellationToken = default)
public Task DeleteAsync(TKey id, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
@ -214,8 +214,8 @@ namespace Volo.Abp.Domain.Repositories
}
public class MyTestCustomBaseRepository<TEntity, TPrimaryKey> : MyTestDefaultRepository<TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>
public class MyTestCustomBaseRepository<TEntity, TKey> : MyTestDefaultRepository<TEntity, TKey>
where TEntity : class, IEntity<TKey>
{
}

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using Volo.Abp.Domain.Entities;
namespace Volo.Abp.TestApp.Domain
@ -25,4 +27,74 @@ namespace Volo.Abp.TestApp.Domain
Type = type;
}
}
public class Order : AggregateRoot<Guid>
{
public virtual string ReferenceNo { get; protected set; }
public virtual float TotalItemCount { get; protected set; }
public virtual DateTime CreationTime { get; protected set; }
public virtual List<OrderLine> OrderLines { get; protected set; }
protected Order()
{
}
public Order(Guid id, string referenceNo)
{
Id = id;
ReferenceNo = referenceNo;
OrderLines = new List<OrderLine>();
}
public void AddProduct(Guid productId, int count)
{
if (count <= 0)
{
throw new ArgumentException("You can not add zero or negative count of products!", nameof(count));
}
var existingLine = OrderLines.FirstOrDefault(ol => ol.ProductId == productId);
if (existingLine == null)
{
OrderLines.Add(new OrderLine(this.Id, productId, count));
}
else
{
existingLine.ChangeCount(existingLine.Count + count);
}
TotalItemCount += count;
}
}
public class OrderLine : Entity
{
public virtual Guid OrderId { get; protected set; }
public virtual Guid ProductId { get; protected set; }
public virtual int Count { get; protected set; }
protected OrderLine()
{
}
public OrderLine(Guid orderId, Guid productId, int count)
{
OrderId = orderId;
ProductId = productId;
Count = count;
}
internal void ChangeCount(int newCount)
{
Count = newCount;
}
}
}
Loading…
Cancel
Save