I've got some models that only have two fields: Id and Name. All this models inherit from IDbDictionary interface.
My goal is to make "universal" controller for CRUD operations for this models. My problem is how to (using EF) modify database table by name. For example, there is method
[HttpPost]
public ActionResult Create(IDbDictionary newRecord, string collectionName)
{
if (ModelState.IsValid)
{
db.<collectionName>.Add(newRecord);
db.SaveChanges();
return View("Success");
}
return View("Create", newRecord);
}
Is there a way to do it the way I described? I thought about reflection, but I've no idea how to do this.
Regards,
C
Usually you would have a Service that would handle your generic database operations which you can call from all your methods. Example:
public class DataService
{
public readonly ApplicationDbContext dbContext;
public DataService(ApplicationDbContext dbContext)
{
this.dbContext = dbContext;
}
public void Create<TEntity>(TEntity entity) where TEntity : IDbDictionary
{
this.dbContext.Set<TEntity>().Add(entity);
this.dbContext.SaveChanges();
}
}
Then in your method you would use:
var dataService = new DataService(this.dbContext);
dataService.Create<ClassName>(newEntity);
Related
I usually use AsNoTracking when I'm not intending to write anything. How should I handle this in my service layer where dbContext is hidden behind it? (I treat EF core as repository because it is repository)
public class SomeService
{
//...
public SomeEntity GetById(int id)
{
return _dbContext.Find(id);
}
public SomeEntity GetReadonlyById(int id)
{
return _dbContext.SomeEntitities.AsNoTracking().SingleOrDefault(e => e.Id == id);
}
public SomeEntity Update(SomeEntity someEntity)
{
_dbContext.Update(someEntity);
_dbContext.SaveChanges();
}
}
public class SomeController
{
private readonly SomeService _someService;
//....
[HttpGet("{id}")]
public IActionResult Get(int id)
{
var someEntity = _someService.GetReadonlyById(id);
if (someEntity == null)
{
return NotFound();
}
return someEntity;
}
[HttpPut("{id}")]
public IActionResult Modify(int id, SomeEntity modified)
{
var someEntity = _someService.GetById(id);
if (someEntity == null)
{
return NotFound();
}
someEntity.Someproperty = modified.Someproperty;
_someService.Update(someEntity);
return Ok(someEntity);
}
}
Is there any better way to do this?
I can also define my service as follows:
public class SomeService
{
//...
public SomeEntity GetById(int id)
{
return _dbContext.AsNoTracking.SingleOrDefault(e => e.Id == id);
}
public SomeEntity Update(int id, SomeEntity someEntity)
{
var entity = _dbContext.SomeEntities.Find(id);
if (entity == null)
{
return null;
}
entity.Someproperty = someEntity.Someproperty;
_dbContext.Update(entity);
_dbContext.SaveChanges();
return entity;
}
}
public class SomeController
{
private readonly SomeService _someService;
//....
[HttpGet("{id}")]
public IActionResult Get(int id)
{
var someEntity = _someService.GetById(id);
if (someEntity == null)
{
return NotFound();
}
return someEntity;
}
[HttpPut("{id}")]
public IActionResult Modify(int id, SomeEntity modified)
{
var someEntity = _someService.Update(id, modified);
if (someEntity == null)
{
return NotFound();
}
return Ok(someEntity);
}
}
What is the better way?
Basically, it is more common problem.
It is often happens that optimized reading methods are not convenient for updating scenarios and convenient reading methods for updating scenarios have unnecessary overhead for reading only scenarios. I see 3 options here:
Ignoring all problems with performance and just use universal GetById from your first approach for reads and updates. Obviously, it is applicable for simple applications and may not be applicable for high-load applications.
Using CQRS. It means you will have completely separate data model for reads and updates. Since reads usually don't require the complex domain logic it allows you to use any optimizations like AsNoTracking method or even use a plain sql in repositories. It is applicable for complex apps and requires more code.
Trying to find some compromise between these two options according to your particular needs.
As noted in comments your SomeService looks like repository. Ideally, domain service should contain only business logic and shouldn't mix it with infrastructure features like AsNoTracking. Whereas repositories can and should contain infrastructure features like AsNoTracking, Include and etc.
No tracking queries are useful when the results are used in a read-only scenario. They are quicker to execute because there is no need to setup change tracking information.
You can swap an individual query to be no-tracking:
using (var context = new BloggingContext())
{
var blogs = context.Blogs
.AsNoTracking()
.ToList();
}
You can also change the default tracking behavior at the context instance level:
using (var context = new BloggingContext())
{
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var blogs = context.Blogs.ToList();
}
Ideally, you should manage the infrastructure stuff in the repository level.
Here is my solution. It works.
BASE CLASS OF ALL SERVICES
public class ServicesBase
{
protected AppDbContext dbcontext { get; }
public ServicesBase(AppDbContext dbcontext)
{
this.dbcontext = dbcontext;
}
public void AsNoTracking()
{
dbcontext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
}
public void SaveChanges()
{
dbcontext.SaveChanges();
}
}
USING IN CONTROLLER
_masterService.AsNoTracking();
var master = _masterService.GetById(1);
master.WagePerSquareMeter = 21;
_masterService.SaveChanges();
//or dbcontext.SaveChanges(), both of them will ot affect the database.
I would like to create a Details view with entity framework data using a repository pattern.
This is my interface repository:
public interface InterfaceRepositroy: IDisposable
{
IEnumerable<SubjectContent> GetAll();
SubjectContent Get(string id);
}
This is the toher repository:
public class SubjectRepository : InterfaceRepositroy,IDisposable
{
private irfwebpage20161013070934_dbEntities2 db;
public IEnumerable<SubjectContent> GetAll()
{
return db.Set<SubjectContent>().ToList();
}
public SubjectContent Get(string id)
{
return db.Set<SubjectContent>().Find(id);
}
public void Dispose()
{
throw new NotImplementedException();
}
}
Here is my controller:
private InterfaceRepositroy subjectreposi;
public ActionResult Details(string id)
{
SubjectContent subject = subjectreposi.Get(id);
return View(subject);
}
My View is a standard details template.
It gets an error at this point in the controller:
SubjectContent subject = subjectreposi.Get(id);
I would really appreciate the help. This is like the fourth version of a repository pattern i am trying to implement but none of them worked so far. I have tried it without interface, with the instance of the subjecrepository or with different linq to sql in the repository. It either gets http error or it doesnt show the data just the names of the data.
Create constructors that initialise your data context:
public SubjectRepository()
{
db = new irfwebpage20161013070934_dbEntities2();
}
public SubjectRepository(irfwebpage20161013070934_dbEntities2 dbContext)
{
db = dbContext;
}
This allows you to either initialise your repository with no parameters which will initialise you data context or specify your own data context.
You can now use this like this:
var repo = new SubjectRepository();
SubjectContent subject = repo.Get(id);
As I was trying to implement code first approach using repository patterns in MVC, I have come across some difficulties as below:
I have a Interface that have few methods declared as below :
public interface IRepository
{
User Getuserdetail(int UserId);
void Save(User Obj);
void delete(int Userid);
void update(User user);
}
Then I have a Repository class which could be using the above interface to define all the methods and will create a seperate layer of Entity Framework:
public class Repository : IRepository
{
RepoDBContext _context;
Repository(RepoDBContext Context)
{
this._context = Context;
}
public User Getuserdetail(int Userid)
{
var user = _context.User.Where(m => m.id == Userid).FirstOrDefault();
return user;
}
public void Save(User user)
{
_context.User.Add(user);
_context.SaveChanges();
}
}
Now could you please check the constructor of this class. The variable this constructor is initializing is type of "RepoDBContext" and the reference type it is using to assign it is also of "RepoDBContext". Is it internally performing like below?
RepoDBContext _context=new RepoDBContext();
My RepoDBContext class is below:
public class RepoDBContext : DbContext
{
public DbSet<User> User { get; set; }
}
Moreover if is the right way to perform then how will i have to call this class in my controller to do some functionality over my user interface. Please guide regarding the same and please don't mind my english. Thanks
I think you already have an answer to the question does assigning a parameter to a field is equivalent to instantiating a new instance of that type as state in the comments and in the answer by Oskar and Kirk.
But I just want go further and try to answer this another question of yours: how will I have to call this class in my controller to do some functionality over my user interface..
If you create your structure using the Repository pattern, you wouldn't want your controllers to handle instances of your DbContext class, because if they do, what is the benefit of having a separated repository layer then? A common pattern that I see people using and I use it myself in several apps is something as follows:
IUserRepository
public interface IUserRepository
{
User GetUserDetail(int userId);
void Save(User user);
void Delete(int userId);
void Update(User user);
}
UserRepository
public class UserRepository : IUserRepository
{
public User GetUserDetail(int userId)
{
using(var _context = new RepoDBContext())
{
return _context.User.Where(m => m.id == userId).FirstOrDefault();
}
}
//other implementations here..
}
Then, you create another layer which will be your Business layer, similar to the Repository.
IUserBusiness
public interface IUserBusiness
{
User GetUserDetail(int userId);
void Save(User user);
void Delete(int userId);
void Update(User user);
}
UserBusiness
public class UserBusiness : IUserBusiness
{
private readonly IUserRepository userRepository;
//CTOR receives a Repository instance via DI
public UserBusiness(IUserRepository userRepository)
{
this.userBusiness = userBusiness;
}
public User GetUserDetail(int userId)
{
//Call repository to get User details
return this.userRepository.GetUserDetail(userId);
}
//other implementations here
}
UserController (example)
public class UserController : Controller
{
private readonly IUserBusiness userBusiness;
//Controller receives a UserBusinnes instance via DI
public UserController(IUserBusiness userBusiness)
{
this.userBusiness = userBusiness;
}
public ActionResult GetDetail(int userId)
{
//Call your "repository" to get user data
var userDetail = userBusiness.GetUserDetail(userId);
//more logic here
}
}
See the difference? Each layer of your application is concerned with one thing. You controller request data to your business layer, which may apply some business rules or validations, and finally call your repository layer which knows how to talk to the database or other storage. Your controller doesn't have any concern about how to create instances of database class or make queries. It just receive a request, ask for data and returns back to the caller.
No, assigning an existing instance of RepoDBContext to a variable is NOT the same as calling new RepoDBContext(). Assignment is just assignment and will not allocate new objects.
Off-topic:
Please also consider that C# coding guidelines suggest that method parameters should be named likeThis (that is, with initial lower case letter). This will make you code more consistent with other .Net code libraries.
Normally I do my data access by instanciating my DbContext globally in my Controller and then I use that manipulate my data.
See below:
public class UserController : Controller
{
private OrtundEntities db = new OrtundEntities();
public ActionResult Create(CreateUserViewModel model)
{
try
{
UserDataModel user = new UserDataModel
{
// map view model fields to data model ones
};
db.Users.Add(user);
db.SaveChanges();
}
catch (Exception ex)
{
// some or other error handling goes here
}
}
}
It occurs to me that this might not be the ideal way to do it in all applications but aside from implementing a web service for every project I do, I can't think of any alternatives to the above.
So what's a better way to handle the data access on larger projects where the above wouldn't be ideal?
I'm just looking for so-called "best practice" for this or that particular situation. Many opinions will differ on what's the best way so what do you think it is and why?
To help keep your controllers concise and free of direct access to your database, you can implement the repository and dependency injection patterns. For even more concise code, you can also use the unit of work pattern.
Say you had this model:
public class Person {
public int Id { get; set; }
public string Name { get; set; }
}
With the help of generics, you can create an interface to provide a CRUD blueprint:
public interface IRepository<T> {
IEnumerable<T> Get();
T Get(int? i);
void Create(T t);
void Update(T t);
void Delete(int? i);
}
Then create a Repository class that implements the IRepository. This is where all your CRUD will take place:
public class PersonRepository : IRepository<Person> {
private OrtundEntities db = new OrtundEntities();
public IEnumerable<Person> Get() {
return db.Persons.ToList();
}
//invoke the rest of the interface's methods
(...)
}
Then in your controller you can invoke the dependency injection pattern:
private IRepository<Person> repo;
public PersonController() : this(new PersonRepository()) { }
public PersonController(IRepository<Person> repo) {
this.repo = repo;
}
And your controller method for, say, Index() could look like this:
public ActionResult Index() {
return View(repo.Get());
}
As you can see this has some useful benefits, including structure to your project, and keeping your controllers easy to maintain.
I think you need to read this
http://chsakell.com/2015/02/15/asp-net-mvc-solution-architecture-best-practices/
Larger proyets ?
Maybe https://msdn.microsoft.com/es-es/library/system.data.sqlclient.sqlcommand(v=vs.110).aspx
I use this in some big requests.
I want to create an abstraction layer between Entity Framework and the rest of my application. But I am having a few problems with Entity Framework.
Basically (I don't show you all the interface layers that I've created too), I've split my application into several projects like this :
Domain
Contains my domain object, an abstraction of my datastorage object
DAL
Creates a link between my datastorage and my business layer. Contains two types of elements :
Private ones : my EDMX, my database object, and some other generated objects providing me some useful methods like ToDomain/ToEntity
Public ones : my Data Access Object, providing CRUD methods
Business
Contains the logic of my application. Only knows about the public elements of the DAL and the Domain Layer.
Presentation
Presents the domain objects for the user. Only knows about the business layer.
As I said, I want to create an abstraction of my datastorage objects (in my case Database object, but I want a solution that works also for file or WCF storage for example) so that my business layer don't know anything about my DAL implementation.
Here is a glimpse of what I've done in my DAL :
public abstract class GenericDao<TEntity, TDomain, TDbContext> : IGenericDao<TDomain>
where TDbContext : DbContext, new()
where TEntity : class
where TDomain : class
{
protected TDbContext _context;
protected DbSet<TEntity> _dbSet;
public GenericDao(TDbContext dbContext)
{
this._context = dbContext;
this._dbSet = dbContext.Set<TEntity>();
}
public TDomain Create()
{
return this.ToDomain(this._dbSet.Create());
}
public IList<TDomain> GetAll()
{
return this._dbSet.ToList().Select(entity => this.ToDomain(entity)).ToList();
}
public void Update(TDomain domain)
{
var entity = this.ToEntity(domain);
var entry = this._context.Entry(entity);
entry.State = EntityState.Modified;
}
public void Remove(TDomain domain)
{
_dbSet.Remove(this.ToEntity(domain));
}
protected abstract TDomain ToDomain(TEntity entity);
protected abstract TEntity ToEntity(TDomain domain);
}
You will probably see what's wrong with my code by reading it: when I try to delete or update an entity, I am not manipulating an entity attached to Entity Framework. If I try to attach my entity to the dbContext, it fails because there is already an entity in the context with the same id.
I already thought about several solutions, but none of them please me.
Maybe am I doing something wrong in my approach? I am a little bit confused about the Repository and DAO pattern (I read anything and the very opposite about that difference on the internet).
You have two options:
initialize new dbcontext for each operation and dispose it when operation is ended:
public abstract class GenericDao<TEntity, TDomain, TDbContext> : IGenericDao<TDomain>
where TDbContext : DbContext, new()
where TEntity : class
where TDomain : class
{
protected Func<TDbContext> _contextFactory;
public GenericDao(Func<TDbContext> contextFactory)
{
_contextFactory = contextFactory;
}
public TDomain Create()
{
using(var context = _contextFactory())
{
return context.Set<TEntity>().Create();
}
}
public IList<TDomain> GetAll()
{
using(var context = _contextFactory())
{
return context.Set<TEntity>().ToList()
.Select(entity => this.ToDomain(entity)).ToList();
}
}
public void Update(TDomain domain)
{
using(var context = _contextFactory())
{
var entity = this.ToEntity(domain);
context.Attach(entity);
var entry = this._context.Entry(entity);
entry.State = EntityState.Modified;
context.SaveChanges();
}
}
public void Remove(TDomain domain)
{
using(var context = _contextFactory())
{
var entity = this.ToEntity(domain);
context.Attach(entity);
context.Set<TEntity>.Remove(entity);
context.SaveChanges();
}
}
protected abstract TDomain ToDomain(TEntity entity);
protected abstract TEntity ToEntity(TDomain domain);
}
or you can try to find entity in your instance of dbcontext using property Local of DbSet:
var contextEntity = context.Set<TEntity>().Local
.Where(c=>c.Id == entity.Id).FirstOrDefault();
You seem to be getting stuck coding to an implementation within your abstraction. If you injected an interface to your generic rather than a concrete type (like EF) then your GenericDao becomes much more flexible. You can inject whatever implementation you choose providing it implements the required interface. In your case, WCF, File, Whatever. For example;
protected IDbContext _context;
public GenericDao(IDbContext dbContext)
{
this._context = dbContext;
}
public void Remove(TDomain domain)
{
_context.Remove(this.ToEntity(domain));
}
//abstraction
public interface IDbContext
{
void Remove(Entity entity);
}
//EF Implementation
public MyEfClass : IDbContext
{
public void Remove(Entity entity)
{
//code to remove for EF example
context.Attach(entity);
context.State = EntityState.Modified;
context.Set<TEntity>.Remove(entity);
context.SaveChanges();
}
}
//WCF Implementation
public MyWCFClass : IDbContext
{
public void Remove(Entity entity)
{
//Wcf implementation here
}
}
//File example
public FileWriter : IDbContext
{
public void Remove(Entity entity)
{
LoadFile();
FindEntry(entity);
WriteFile(entity);
SaveFile();
}
public void LoadFile()
{
//use app settings for file directory
}
}