GodelTech.Microservices.EntityFrameworkCore
project allows users easy to use Entity Framework Core with patterns Repository and Specification.
Entity Framework Core. This ORM is recommended for new projects. It allows microservice to be run without operating system constraints. E.g. Linux and Windows operating systems can be used.
In order to use EF Core ORM the following initializer must be added to Startup.CreateInitializers()
method:
yield return new EntityFrameworkInitializer<WeatherForecastDbContext>(Configuration);
In order to use GoldeTech entity framework few simple steps are required:
- Create ASP.NET Website application using Visual Studio or dotnet cli.
- Reference latest versions of
GodelTech.Microservices.Core
andGodeTech.Microservices.EntityFrameworkCore
nuget packages and optionally satellite packages you would like to use. - Setup the project as described in the GodelTech.Microservices.Core manual.
- Add congiguration GodelTech Entity Framework Core to
Startup.cs
CreateInitializers()
method:
yield return new EntityFrameworkInitializer<WeatherForecastDbContext>(Configuration);
where WeatherForecastDbContext
is a class that was inherited from DbContext
class
public class WeatherForecastDbContext : DbContext
public WeatherForecastDbContext(DbContextOptions<WeatherForecastDbContext> contextOptions)
: base(contextOptions)
{ }
- Setup entities and relationships between them, folowing Entity Framework Core instruction.
Please see the following snippet to configure Db context for two models with one-to-many relationship:
WeatherForecastDbContext.cs
public class WeatherForecastDbContext : DbContext
{
public DbSet<PrecipitationType> PrecipitationTypes { get; set; }
public DbSet<Precipitation> Precipitations { get; set; }
public WeatherForecastDbContext(DbContextOptions<WeatherForecastDbContext> contextOptions)
: base(contextOptions)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(typeof(Precipitation).Assembly);
}
}
Precipitation.cs
public class Precipitation
{
public int Id { get; set; }
public string Town { get; set; }
public DateTime DateTime { get; set; }
public int Temperature { get; set; }
public string Summary { get; set; }
public int PrecipitationTypeId { get; set; }
public PrecipitationType PrecipitationType { get; set; }
}
PrecipitationType.cs
public class PrecipitationType
{
public int Id { get; set; }
public string Name { get; set; }
}
PrecipitationConfiguration.cs
public class PrecipitationConfiguration : IEntityTypeConfiguration<Precipitation>
{
public void Configure(EntityTypeBuilder<Precipitation> builder)
{
builder.HasKey(p => p.Id);
builder.Property(p => p.Id).IsRequired();
builder.Property(p => p.Town).IsRequired();
builder.Property(p => p.Temperature).IsRequired();
builder.Property(p => p.DateTime).IsRequired();
builder.Property(p => p.PrecipitationTypeId);
builder.HasOne(x => x.PrecipitationType).WithMany().HasForeignKey(x => x.PrecipitationTypeId);
}
}
For CRUD operation GodeTech.Microservices.EntityFrameworkCore
proposes using pattern Repository.
In order to use Repository for get, create, update and delete operetions see the flow below:
- Declare a property with type
IRepository<T>
whereT
is entity
private readonly IRepository<Precipitation> _precipitationRepository;
- Resolve dependency in constructor
public WeatherForecastController(IRepository<Precipitation> precipitationRepository)
{
_precipitationRepository = precipitationRepository;
}
- Use repository to execute query
[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
Precipitation precipitation = await _precipitationRepository.GetByIdAsync(id);
return Ok(precipitation);
}
- Use the same way for Delete operation.
[HttpDelete("{id}")]
public async Task<IActionResult> Delete(int id)
{
Precipitation precipitation = await _precipitationRepository.GetByIdAsync(id);
await _precipitationRepository.DeleteAsync(precipitation);
return Ok();
}
- For Add and Update operations use samples below.
await _precipitationRepository.AddAsync(precipitation);
await _precipitationRepository.UpdateAsync(precipitation);
Sometimes it is necessary to get data by conditions. In this case GodeTech.Microservices.EntityFrameworkCore
proposes using pattern Specification.
- Create a specification class for each entity and inherite it from
Specification<T>
whereT
is entity
public class PrecipitationSpecification : Specification<Precipitation>
- Define nullable fields for the conditions to be used.
public string Town { get; set; }
public int? Temperature { get; set; }
- Build query in override method
AddPredicates
public override IQueryable<Precipitation> AddPredicates(IQueryable<Precipitation> query)
{
if (Temperature.HasValue)
{
query = query.Where(x => x.Temperature == Temperature);
}
if (!string.IsNullOrWhiteSpace(Town))
{
query = query.Where(x => x.Town.Contains(Town));
}
}
- Use specification class
[HttpGet("temperature/{temperature}/town/{town}")]
public async Task<IActionResult> GetList(int temperature, string town)
{
var spec = new PrecipitationSpecification
{
Temperature = temperature,
Town = town
};
var precipitations = await _precipitationRepository.ListAsync(spec);
return Ok(precipitations);
}
- Override the method
AddSorting(IQueryable<Precipitation> query)
inPrecipitationSpecification
class to set sorting rules
public override IQueryable<Precipitation> AddSorting(IQueryable<Precipitation> query)
{
return query.OrderBy(c => c.Town);
}
- Override the method
AddEagerFetching(IQueryable<Precipitation> query)
inPrecipitationSpecification
class to include related entities
public override IQueryable<Precipitation> AddEagerFetching(IQueryable<Precipitation> query)
{
if (IncludePrecipitationType.HasValue)
{
query = query.Include(x => x.PrecipitationType);
}
return query;
}
In order to use stored procedure see code below:
public class PrecipitationQuery : IPrecipitationQuery
{
private readonly WeatherForecastDbContext _dbContext;
public PrecipitationQuery(WeatherForecastDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<IList<Precipitation>> GetListAsync()
{
return await _dbContext.Precipitations.FromSqlRaw("GetPrecipitations").ToListAsync();
}
}
NOTE At the service start, all migrations are applied. Database is created if it is not exist.