I'm new to the forum and in the "world" of programming. I bumped into a problem while creating a game with SignalR Web technology and it is expressed in terms of access to the database (using EF) with multiple requests from UI-a. What is the best solution using the repository pattern? The decision to me at this stage is added Lock {} structure in each method, which accesses the database. How can I avoid blocking requests to a server?
public interface IRepository<T> where T : class
{
IQueryable<T> GetAll();
T GetById(object id);
void Add(T item);
void Update(T item);
void Delete(T item);
void Delete(object id);
}
public class DBRepository<T> : IRepository<T> where T : class
{
private DbContext DbContext;
private DbSet<T> Entities
{
get
{
return this.DbContext.Set<T>();
}
}
public DBRepository(DbContext context)
{
this.DbContext = context;
}
public IQueryable<T> GetAll()
{
return Entities.AsQueryable();
}
.....
public class TicTacToeContext : DbContext
{
public DbSet<Game> Games { get; set; }
public DbSet<Guess> Guesses { get; set; }
public DbSet<Message> Messages { get; set; }
public DbSet<MessageState> MessageStates { get; set; }
public DbSet<MessageType> MessageTypes { get; set; }
public DbSet<User> Users { get; set; }
public TicTacToeContext()
: base("TicTacToeDb")
{
}
public interface IGameService
{
void CreateGame(CreateGameModel gameModel);
void JoinGame(JoinGameModel gameModel);
...
public abstract class BaseService
{
public IRepository<User> UserRepository;
public IRepository<Game> GameRepository;
...
public class GameService : BaseService, IGameService
{
public GameService(IRepository<Game> gameRepositort, IRepository<User> userRepository, ISessionService sessionService)
{
this.UserRepository = userRepository;
this.GameRepository = gameRepositort;
}
public void CreateGame(CreateGameModel gameModel)
{
....
}
public class TicTacToeHub : Hub
{
IUserService UserServise;
IGameService GameServise;
private static object _syncRoot = new object();
public TicTacToeHub(IUserService userService, IGameService gameService)
{
this.UserServise = userService;
this.GameServise = gameService;
}
.....
public void ReturnOpenGamesToClient(string sessionKey)
{
IEnumerable<GameModel> openGames;
lock (_syncRoot)
{
openGames = GameServise.GetOpenGames(sessionKey).ToList();
}
Clients.Caller.updateOpenGamesList(openGames);
}
Why locks? You use a DB and only update one entity (No transaction scope needed).
Locks needs to be used for Inmemory types like IList or IDictionary otherwise it will crash when one request reads and another one writes. But SQL takes care of this for you
Related
Here is my code and I want to create API, from the repository methods.
This is Entity table of my code:
public partial class Course
{
public int ID { get; set; }
public string Name { get; set; }
public int DepartmentID { get; set; }
[ForeignKey("DepartmentID")]
public virtual Department Department { get; set; }
public int GradeLevelsID { get; set; }
[ForeignKey("GradeLevelsID")]
public virtual GradeLevels GradeLevels { get; set; }
// Navigation
public virtual ICollection<Units> Units { get; set; }
}
I need some output according to the methods:
Create course for the particular Gradelevel
Get Course of the GradeLevel
Get All Unit of the course
I write code for the following condition in the IRepository
Public interface ICourseRepository
{
Task<Course> GetAllCourseByGradeLevleId(int id)
Task<Course> UpdateCoursetAsync(int Id);
Task<Action> CreateCourseAsync(Course Course);
Task<Course> DeleteCourseAsync(int Id);
}
And the Repository Methods will be as following:
public class CountryRepository : ICourseRepository
{
public Task<Action> CreateCourseAsync(Course Course)
{
throw new NotImplementedException();
}
public Task<Course> DeleteCourseAsync(int Id)
{
throw new NotImplementedException();
}
public Task<Course> GetAllCourseByGradeLevleId(int id)
{
throw new NotImplementedException();
}
public Task<Course> UpdateCoursetAsync(int Id)
{
throw new NotImplementedException();
}
My Problem is that I am unable to write return type method and unable to fetch data from the relational table, as well as unable to write POST and PUT api for this conditions.
Here is my controller class:
[Route("api/[controller]")]
[ApiController]
public class CourseController : ControllerBase
{
private readonly ICourseRepository _courseRespository;
public CourseController(ICourseRepository courseRespository)
{
_courseRespository = courseRespository;
}
[HttpGet]
public async Task<IEnumerable<Course>> Get()
{
return await _courseRespository.GetAllCourseAsync();
}
public async Task<ActionResult<Course>> GetId(int id)
{
var result = await _courseRespository.GetAllCourseByIdAsync(id);
if (result == null)
{
return NotFound();
}
return result;
}
[HttpPost]
public async Task<ActionResult> Post(Course course)
{
// _courseRespository.CreateCourseAsync();
// await _courseRespository.SaveChangesAsync();
return CreatedAtAction("GetId", new { id = course.ID }, course);
}
How can write PUT and POST in this condition.
Try having a code like below,
[Route("Course")]
public class CountryRepository : ICourseRepository
{
[Route("~/users/Create")]
[ResponseType(typeof(Course))]
[HttpPost]
public async Task<Action> CreateCourseAsync(Course Course)
{
return Request.CreateResponse(HttpStatusCode.OK, resultObj);
}
}
I have model:
public class Department
{
public int DepartmentID { get; set; }
[Required]
[UniqueDepartmentName]
public string Name { get; set; }
public List<Person> Persons { get; set; }
}
And DBcontext:
public class InstituteContext : DbContext
{
public InstituteContext (DbContextOptions<InstituteContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Department>().HasIndex(p => p.Name).IsUnique();
}
public DbSet<Institute.Models.Department> Department { get; set; }
}
As you see property "NAME" i make unique.
For validation i create My validation Attribute:
public class UniqueDepartmentName : ValidationAttribute
{
public override bool IsValid(object value)
{
var db = new InstituteContext();
}
}
But i can not create instance of InstituteContext, because constructor need parameters.
How i can create instance of InstituteContext? Or what should i pass to constructor in parameters?
Try this:
public class UniqueDepartmentName : ValidationAttribute
{
public override bool IsValid(object value)
{
var connectionString = "Your ConnectionString"
var options = new DbContextOptionsBuilder<InstituteContext>()
.UseSqlServer(new SqlConnection(connectionString)).Options;
using (var dbContext = new BloggingContext(options))
{
// Do necessary staffs here with dbContext
}
}
}
Your DbContextOptions method is in the wrong place, your constructor can be empty, and you need to add the method OnConfiguring, which receives the DbContextOptions.
Something like:
public DbSet<Department> Department { get; private set; }
protected override void OnConfiguring(DbContextOptionsBuilder options) {
// In my case I'm passing the connection string in this method below
options.UseSqlServer("Data Source=DATABASEIP;Initial Catalog=DATABASETABLE;" +
"User ID=USER;Password=PASSWORD");
}
I am trying to use Repository/UoW Patternin a .net core project . I have looked at many implementations across web . In all the implementations repositories are created as properties in IUnitOfWork.
In Future if we have 50 Repositories we need to have 50 properties in the Unit of Work . Could anyone suggest a better approach for implementing Repository/UoW.
Please Find below the code snippets of approach i have implemented currently.
IUnitOfWork.cs
IStudentRepository Student { get; set; }
IClassRepository Class { get; set; }
void Complete();
UnitOfWOrk.cs
public class unitofwork {
private readonly CollegeContext _context;
IStudentRepository Student { get; set; }
IClassRepository Class { get; set; }
public UnitOfWork(CollegeContext CollegeContext)
{
this._context = CollegeContext;
Student = new StudentRepository(_context);
Class = new ClassRepository(_context);
}
public void Complete()
{
return _context.SaveChanges();
}
}
Student and Class Repositories Inherit From a generic Repository class and IStudentRepository and IClassRepository respectively.
StudentRepository.cs
public class StudentRepository : Repository<Student> , IStudentRepository
{
private readonly CollegeContext context;
private DbSet<Student> entities;
public StudentRepository(CollegeContext context) : base(context)
{
this.context = context;
entities = context.Set<Student>();
}
}
Property-per-Repository is not convenient in some cases as you said. I generally use some sort of factory method in UoW class as below:
public class unitofwork
{
private readonly CollegeContext _context;
IStudentRepository Student { get; set; }
IClassRepository Class { get; set; }
public UnitOfWork(CollegeContext CollegeContext)
{
this._context = CollegeContext;
}
public T CreateRepository<T>() where T : IRepository
{
IRepository repository = null;
if(typeof(T) == typeof(IStudentRepository))
repository = new StudentRepository(_context);
......
......
else
throw new XyzException("Repository type is not handled.");
return (T)repository;
}
public void Complete()
{
return _context.SaveChanges();
}
}
public interface IRepository
{
Guid RepositoryId { get; }
}
My IRepository just hold a simple property. You may extend this interface as per your needs.
I work with Asp.Net Core WebApi project.
Can I add my tables to IdentityDbContext, like this:
public class ApplicationDbContext : IdentityDbContext<User>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{ }
public DbSet<ProgrammerRole> ProgrammerRoles { get; set; }
public DbSet<Project> Projects { get; set; }
public DbSet<SubProject> SubProjects { get; set; }
public DbSet<Report> Reports { get; set; }
}
Or do I need to create a second DbContext. And if i create a second DbContext
how can I communicate wiht User in IdentityDbContext.
And my second question:
If i add data in IdentityDbContext, like above, How do I get the data from my tables in ApplicationDbContext?
Because i need to pass DbContextOptions object every time I create a new instance оf ApplicationDbContext. I do this in Startup.cs:
// ===== Add DbContext ========
var connectionString = Configuration.GetConnectionString("DbConnection");
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
I saw in older version of Asp.Net Core, that i can pass Connection String in IdentityDbContext constructor, but now only DbContextOptions.
And i can't do, for example this:
[AllowAnonymous]
[HttpGet]
public IEnumerable<Project> GetRoles()
{
using (var db = new ApplicationDbContext())
{
return db.Projects;
}
}
Can I add my tables to IdentityDbContext, like this:
Yes, it is how you create custom tables. You do not need to create another DbContext. E.g.
public class Project
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Project> Projects { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Project>(entity =>
{
entity.Property(e => e.Name)
.IsRequired()
.HasMaxLength(50);
});
base.OnModelCreating(builder);
}
}
Note: you might need to run dotnet ef migrations add Initial and dotnet ef database update for database migration.
using (var db = new ApplicationDbContext()) {...}
You should not create or manage ApplicationDbContext inside controller. If you do so, they become tightly coupled, and you cannot implement unit tests.
Instead, you let dependency inversion (DI) container manage it for you. E.g.
public class UserController : Controller
{
private readonly ApplicationDbContext _context;
public UserController(ApplicationDbContext context)
{
_context = context;
}
[AllowAnonymous]
[HttpGet]
public IEnumerable<Project> GetRoles()
{
return _context.Projects;
}
}
I solve my problem, i just replaced code in my ApplicationDbContext, and get connection string from method:
public class ApplicationDbContext : IdentityDbContext<User>
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(GetConnectionString());
}
private static string GetConnectionString()
{
const string databaseName = "EmployeeReportsDb";
const string databasePass = "SuperPuper_Random_DB-key!";
return $"Server=localhost;" +
$"database={databaseName};" +
$"Trusted_Connection = True;" +
$"MultipleActiveResultSets = True;" +
$"pwd={databasePass};" +
$"pooling=true;";
}
public DbSet<ProgrammerRole> ProgrammerRoles { get; set; }
public DbSet<Project> Projects { get; set; }
public DbSet<SubProject> SubProjects { get; set; }
public DbSet<Report> Reports { get; set; }
}
here is the resource: https://medium.com/#ozgurgul/asp-net-core-2-0-webapi-jwt-authentication-with-identity-mysql-3698eeba6ff8
I am trying a MVC project with repository pattern and unit of work.
The following is from my InitOfWork
public interface IUnitOfWork
{
IRepository<User> UserRepository { get; }
void Save();
}
and this is from UnitOfWork
public class UnitOfWork:IUnitOfWork, IDisposable
{
private JNContext context = new JNContext();
private bool disposed = false;
private IRepository<User> userRepository;
public IRepository<User> UserRepository
{
get
{
if (this.userRepository == null)
{
this.userRepository = new Repository<User>(this.context);
}
return this.userRepository;
}
}
public void Save()
{
this.context.SaveChanges();
}}
The following line in UnitOfWork generates the error 'Cannot implicitly convert from Repository to IRepository
this.userRepository = new Repository<User>(this.context);
What am I missing. I cannot find an answer and I am stuck the entire day.
Try something like this
public interface IRepository<T> where T : class
{
IQueryable<T> Entities { get; }
void Remove(T entity);
void Add(T entity);
}
public class GenericRepository<T> : IRepository<T> where T : class
{
private readonly MyDbContext _dbContext;
private IDbSet<T> _dbSet => _dbContext.Set<T>();
public IQueryable<T> Entities => _dbSet;
public GenericRepository(MyDbContext dbContext)
{
_dbContext = dbContext;
}
public void Remove(T entity)
{
_dbSet.Remove(entity);
}
public void Add(T entity)
{
_dbSet.Add(entity);
}
}
Found a good article about it here: https://medium.com/#utterbbq/c-unitofwork-and-repository-pattern-305cd8ecfa7a