How to pass Dbset object as a parameter to any user define function in entity framework code first? - asp.net-mvc

I want to pass Dbset Object to my method.
This is my Method:
public static class MyClass
{
public static Floor ReturnObject(this DbSet<Floor> floor, int Id)
{
var context = floor.passContext() as MyDBContext;
var data = context.floors.Where(a =>a.Id == Id).FirstOrDefault();
return ad;
}
}
public class MyDBContext: DbContext
{
public DbSet<Floor> floors { get; set; }
}
public static DbContext passContext<TEntity>(this DbSet<TEntity> dbSet)
where TEntity : class
{
//code....
}
Now i want to use my method of static class MyClass that is ReturnObject.
I want to use ReturnObject method in my Controller.
I know i can declare it as private member like this in my controller:
This is my controller:
public class MyController
{
private DbSet<Floor> floor;//but is this a good way???
public ActionResult Index(int Id)
{
var data=MyClass.ReturnObject(????,Id)//what should come in place of question mark??
}
}
How should i pass my First Parameter to ReturnObject Method???

Change your ReturnObject method. It should only take Id as parameter and filter data than return object of Floor.
public static Floor ReturnObject(int Id)
{
using(MyDBContext context = new MyDBContext())
{
var data = context.floors.Where(a =>a.Id == Id).FirstOrDefault();
return ad;
}
}
And when you call it than only pass id as paramter
var data=MyClass.ReturnObject(Id);
This will return object of floor which will be stored in data.

Related

Generic repository pattern and multiple selects

I am trying to learn the repository pattern and looking at a generic repository I cannot see how to handle customized select statements. For example, using this article the author uses a select by ID and a select all.
public interface IGenericRepository<T> where T:class
{
IEnumerable<T> SelectAll();
T SelectByID(object id);
void Insert(T obj);
void Update(T obj);
void Delete(object id);
void Save();
}
Later the article the IGenericRepository interface is implemented using Northwind. Then that is used to create a Customer controller.
public class CustomerController : Controller
{
private IGenericRepository<Customer> repository = null;
public CustomerController()
{
this.repository = new GenericRepository<Customer>();
}
...
This would handle selecting a list of all Customers or for one Customer by ID but where I get stuck is some more real world examples like "select all Customers for a client" or "select all Customers for a region". Plus, you could have another controller based on a different entity that would filter on different attributes. I assume I'm missing something basic. If the user interface needed to present the Customer entity (or any other entity) by various filters, how would this be done by sticking with one generic repository?
Here you go; to handle any select criteria apart from the Id, you can add Where method
like below
public interface IGenericRepository<T> where T:class
{
IEnumerable<T> SelectAll();
T SelectByID(object id);
IEnumerable<T> Where(Expression<Func<T,bool>> predicate)// this one
void Insert(T obj);
void Update(T obj);
void Delete(object id);
void Save();
}
Now in the Where method implementation do it like this
public IEnumerable<T> Where(Expression<Func<T,bool>> predicate)
{
return _objectSet.Where(predicate).AsEnumerable();
}
Here _objectSet in created in repository constructor like this :
public Repository(ObjectContext context)
{
_context = context;
_objectSet = _context.CreateObjectSet<T>();
}
public CustomerController()
{
_context = new NorthwindEntities();
_reporsitory = new Repository<Customer>(_context);
}
Use of Where method like
reporsitory.Where(c=>c.Country=="Canada").ToList();
For full reference see this project on codeplex (download /browse source code)
https://efgenericrepository.codeplex.com/SourceControl/latest
I think the implementation of the GenericRepository should somehow be able to return the IQueryable of current entity, like adding Get() method.
protected IQueryable<T> Get() // Notice that the access modifier is protected.
{
return table;
}
Then you could just create a derived class from GenericRepository and add a select method that accepts the Filter class.
public class CustomerRepository : GenericRepository<Customer>
{
public IEnumerable<T> SelectAll(CustomerFilter filter){ .. }
}
The filter class contains 2 filters.
public class CustomerFilter
{
public int? ClientId { get; set; }
public int? RegionId { get; set; }
}
Then the SelectAll implementation would be.
public IEnumerable<T> SelectAll(CustomerFilter filter)
{
var query = Get();
if (filter == null)
{
return query;
}
if (filter.ClientId.HasValue)
{
query = query.Where(q => q.ClientId == filter.ClientId.Value);
}
if (filter.RegionId.HasValue)
{
query = query.Where(q => q.RegionId == filter.RegionId.Value);
}
return query;
}
In the controller, calling it like.
public ActionResult Get(int? clientId, int? regionId)
{
var filter = new CustomerFilter { ClientId = clientId, RegionId = regionId };
var customers = _repository.SelectAll(filter);
return View();
}
You might need to see this post as your reference.
An approach I've seen in one asp.net mvc based mission critical app, is to use the generic interface as defined in the question. Then there is an abstract class that implements that interface. And there is one more repository class that inherits the abstract class, which has all methods specific to that class.
public interface IGenericRepository<T> where T:class
{
...
}
public abstract class GenericRepository<T> : IGenericRepository where T:class
{
...
}
And the CustomerRepository class
public class CustomerRepository : GenericRepository<Customer>
{
//add method specific to Customer like select Customers in specific country
}
And in the controller
public class CustomerController : Controller
{
private CustomerRepository repository = null;
public CustomerController()
{
this.repository = new CustomerRepository();
}
...

Intranet Application - Data Access in separate project

I have an MVC intranet application which uses EF 6. I have setup the DataAccess project in a separate class library which has EF 6 referenced. I have an entity which implements an interface:
public interface IAuditable
{
DateTime CreatedDateTime { get; set; }
string CreatedBy { get; set; }
}
public class Collection : IAuditable
{
// Properties
}
However, in the SaveChanges method I obviously don't have access to HttpContext.Current.User.Identity.Name as it is in a separate class library, so I was wondering how one would set this in SaveChanges?
public override int SaveChanges()
{
var addedEntries = ChangeTracker.Entries().Where(x => x.State == EntityState.Added);
foreach (var dbEntityEntry in addedEntries)
{
var entity = dbEntityEntry.Entity as IAuditable;
if (entity != null)
{
entity.CreatedDateTime = DateTime.Now;
// how do I set entity.CreatedBy = HttpContext.Current.User.Identity.Name?
}
}
return base.SaveChanges();
}
Edit
Following on from #CodeCaster solution, I have the following:
[BreezeController]
public class BreezeController : ApiController
{
private readonly BTNIntranetRepository _repository;
public BreezeController(BTNIntranetRepository repository)
{
_repository = repository;
_repository.LoggedInUser = HttpContext.Current.User.Identity.Name;
}
// Methods
}
But HttpContext.Current.User is null
This can be solved in many ways.
You're not really showing relevant code, but you can for example give the library class you expose a public string LoggedInUser (or ActingUser or give it a name) property which you set when instantiating it:
public class SomeController : Controller
{
private IDataSource _dataSource;
public SomeController(IDataSource dataSource)
{
_dataSource = dataSource;
_dataSource.LoggedInUser = HttpContext.Current.User.Identity.Name
}
}
You can then simply use that property in your IDataSource.SaveChanges() method:
public override int SaveChanges()
{
// ...
entity.CreatedBy = this.LoggedInUser;
}

How to cast a class to an interface using generics in c#?

I've this interface:
public interface IRepository<T>
{
List<T> List();
T Get(int Id);
bool Add(T entity);
bool Update(T entity);
}
And I've this class:
public class Customer<T> : IRepository<Entities.Customer>
{
public Entities.Customer Get(int Id)
{
var c = new Entities.Customer();
return c;
}
//continue...
}
How can I cast a generic class to a generic interface like so:
//Other method
public IRepositorio<T> DoStuff<T>(int Id)
{
var a = (IRepository<Entities.Customer>)Activator.CreateInstance(typeof(T)); // ok
var b = (IRepository<T>)Activator.CreateInstance(typeof(T)); // Exception: unable to cast
return object; // an object
}
And I call from this MCV controller:
public ActionResult Home()
{
var repo = new Repository();
repo.DoStuff<Customer<Entities.Custormer>>(10);
return View();
}
My conception is ok? This is possible without dynamic?
Based on the code supplied, I've tried the following which compiles OK
public class Entities {
public class Customer {
}
}
public interface IRepository<T> {
T Get(int Id);
}
public class Customer<T> : IRepository<Entities.Customer> {
public Entities.Customer Get(int Id) {
var cliente = new Entities.Customer();
return cliente;
}
}
public class foo {
public static IRepository<T> DoStuff<T>(int Id) {
var a = (IRepository<Entities.Customer>)Activator.CreateInstance(typeof(T));
var b = (IRepository<T>)Activator.CreateInstance(typeof(T));
return b; // an object
}
}
However, I'm not sure what T is meant to be. When I run and call
foo.DoStuff<Entities.Customer>(0);
then I get a runtime error on the var a line, because the class Entities.Customer does not implement the interface IRepository<T>. If I call
foo.DoStuff<Customer<Entities.Customer>>(0);
then I get the runtime error on the 'var b' line, because the class Customer<Entities.Customer> implements IRepository<Entities.Customer> and not IRepository<Customer<Entities.Customer>>
Both exceptions are correct, so hopefully the author of the question can work out where the problem lies from this answer.
Activator.CreateInstance(typeof(T)); - this creates for you new instance of T, which is Entities.Customer in your example, but it looks like you want to create instance of Customer<Entities.Customer>.

Best Practice for fill ViewModel with different Repositories

I'm trying to find out the best way to doing this code
(because I think, my way locks not good):
I've tried to make it as easy to understand the problem.
public ActionResult Index()
{
var user=new User();
user.load(1);
return View(user);
}
load(int id )
{
//pseudocode:
//1. load user from repository1
//2. load address from repository2
//3.load payments from repository3
}
Here you go
We would first create a UserModelService as below
public class UserModelService
{
public User Load(int id)
{
var userRepository = new UserRepository();
var user = userRepository.Load(id);
var addressRepository = new AddressRepository();
user.Address = addressRepository.LoadForUserId(id);
return user;
}
}
We would then modify the original code in controller as below
public ActionResult Index()
{
var userModelSerice =new UserModelService();
var user = userModelService.load(1);
return View(user);
}
All the remaining code reference above is as below
public class AddressRepository
{
public Address LoadForUserId(int id)
{
// Load the address for given user id
}
}
public class UserRepository
{
public User Load(int id)
{
// Load and return user
}
}
public class User
{
public Address Address { get; set; }
}
public class Address
{
}
Now in your controller action, instead of creating a new instance of UserModelService, you can have it injected through constructor. Similar principle can be applied to inject the repositories into UserModelService but that would be another big discussion so I would cut myself short here.

Get/Set HttpContext Session Methods in BaseController vs Mocking HttpContextBase to create Get/Set methods

I created Get/Set HttpContext Session Methods in BaseController class and also Mocked HttpContextBase and created Get/Set methods.
Which is the best way to use it.
HomeController : BaseController
{
var value1 = GetDataFromSession("key1")
SetDataInSession("key2",(object)"key2Value");
Or
var value2 = SessionWrapper.GetFromSession("key3");
GetFromSession.SetDataInSession("key4",(object)"key4Value");
}
public class BaseController : Controller
{
public T GetDataFromSession<T>(string key)
{
return (T) HttpContext.Session[key];
}
public void SetDataInSession(string key, object value)
{
HttpContext.Session[key] = value;
}
}
Or
public class BaseController : Controller
{
public ISessionWrapper SessionWrapper { get; set; }
public BaseController()
{
SessionWrapper = new HttpContextSessionWrapper();
}
}
public interface ISessionWrapper
{
T GetFromSession<T>(string key);
void SetInSession(string key, object value);
}
public class HttpContextSessionWrapper : ISessionWrapper
{
public T GetFromSession<T>(string key)
{
return (T) HttpContext.Current.Session[key];
}
public void SetInSession(string key, object value)
{
HttpContext.Current.Session[key] = value;
}
}
The second one seems the best. Although I would probably write those two as extension methods to the HttpSessionStateBase instead of putting them into a base controller. Like this:
public static class SessionExtensions
{
public static T GetDataFromSession<T>(this HttpSessionStateBase session, string key)
{
return (T)session[key];
}
public static void SetDataInSession<T>(this HttpSessionStateBase session, string key, object value)
{
session[key] = value;
}
}
and then inside the controllers, or helpers, or something that has an instance of HttpSessionStateBase use it:
public ActionResult Index()
{
Session.SetDataInSession("key1", "value1");
string value = Session.GetDataFromSession<string>("key1");
...
}
Writing session wrappers is useless in ASP.NET MVC as the HttpSessionStateBase provided by the framework is already an abstract class which could be easily mocked in unit tests.
Just a little correction for the SetDataInSession method of the latest post. In my opinion, it´s a elegant solution! Thanks Darin Dimitrov.
public static class SessionExtensions
{
public static T GetDataFromSession<T>(this HttpSessionStateBase session, string key) {
return (T)session[key];
}
public static void SetDataInSession(this HttpSessionStateBase session, string key, object value) {
session[key] = value;
}
}
First create this class, and after remember to refer its namespace in the Controller class that will call this methods.
When getting the session value:
string value = Session.GetDataFromSession<string>("key1");
The must be a compatible type with the object persisted in the session.

Resources