I currently have a method that allows me to generate an IEnumerable object for my dropdown list in my web app forms.
Example of current code :
//Name with Id
StateListDp = _db.States.ToDropdownList(c => c.Name, c => Convert.ToString(c.Id, CultureInfo.InvariantCulture));
//Description with Id
StatusesListDp = _db.Statuses.ToDropdownList(c => c.Description, c => Convert.ToString(c.Id, CultureInfo.InvariantCulture));
I've just implemented Repository Design Pattern.
I'm able to convert it over to this now :
StateListDp = unitOfWork.State.GetDropDownList().ToList();
StatusesListDp = unitOfWork.Status.GetDropDownList().ToList();
I've created the following support class (I've excluded the unitOfWork for now )
public class StatusRepository : Repository<Statuses>, IStatusRepository
{
private readonly TenDDbContext context;
public StatusRepository(TenDDbContext context): base(context)
{
this.context = context;
}
public IEnumerable<Statuses> GetAllActive()
{
return Find(x => x.IsActive == true);
}
public IEnumerable<SelectListItem> GetDropDownList()
{
return GetAllActive()
.ToDropdownList(c => c.Description, c => Convert.ToString(c.Id, CultureInfo.InvariantCulture));
}
}
public class StateRepository : Repository<States>, IStateRepository
{
private readonly TenDDbContext context;
public StateRepository(TenDDbContext context): base(context)
{
this.context = context;
}
public IEnumerable<States> FindAllActive(Expression<Func<States, bool>> predicate)
{
return Find(predicate).Where(x => x.IsActive == true);
}
public IEnumerable<States> GetAllActive()
{
return Find(x => x.IsActive == true);
}
public IEnumerable<SelectListItem> GetDropDownList()
{
return GetAllActive()
.ToDropdownList(c => c.Name, c => Convert.ToString(c.Id, CultureInfo.InvariantCulture));
}
}
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
private readonly TenDDbContext context;
public Repository(TenDDbContext context)
{
this.context = context;
}
public TEntity Add(TEntity entity)
{
return context.Set<TEntity>().Add(entity).Entity;
}
//public bool save(TEntity entity)
//{
// var test= Add(entity);
// test.
//}
public void AddRange(IEnumerable<TEntity> entities)
{
context.Set<TEntity>().AddRange(entities);
}
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return context.Set<TEntity>().Where(predicate);
}
public TEntity SingleOrDefault(Expression<Func<TEntity, bool>> predicate)
{
return context.Set<TEntity>().SingleOrDefault(predicate);
}
public TEntity Get(int id)
{
return context.Set<TEntity>().Find(id);
}
public IEnumerable<TEntity> GetAll()
{
return context.Set<TEntity>().ToList();
}
public TEntity Update(TEntity entity)
{
//context.Attach(entity).State = EntityState.Modified;
// context.Attach(entity);
//return context.Entry(entity).State = EntityState.Modified;
return context.Update(entity)
.Entity;
}
public void Remove(TEntity entity)
{
context.Set<TEntity>().Remove(entity);
}
public void RemoveRange(IEnumerable<TEntity> entities)
{
context.Set<TEntity>().RemoveRange(entities);
}
}
So my issue is that I have 10 or so tables that I will need to retrieve this very similar data from.
I'm wondering there is a way to make the GetDropDownList a generic method?
So that I can limit the amount of repeat code ...
I'm even willing to make it two methods
GetDropDownNameList and GetDropDownDescriptionList
adding dropdownextension method
public static IEnumerable<SelectListItem> ToDropdownList<T>(this IEnumerable<T> items,
Func<T, string> text, Func<T, string> value = null, Func<T, Boolean> selected = null)
{
var listData = items.Select(p => new SelectListItem
{
Text = text.Invoke(p),
Value = (value == null ? text.Invoke(p) : value.Invoke(p)),
Selected = selected != null && selected.Invoke(p)
});
var defaultRow = new SelectListItem() { Value = "0", Text = "Please Select One", Selected = V };
var newList = listData.Prepend(defaultRow);
//return new SelectList(newList, "Value", "Text");
return newList;
}
passing the selection of the props for description and key should do the trick. If you want to make it even more generic to be inside the IRepository, replace GetAllActive() with a filter
public IEnumerable<SelectListItem> GetDropDownList(Expression<Func<TEntity, string>> predicateDescription, Expression<Func<TEntity, string>> predicateKey)
{
return GetAllActive().ToDropdownList(predicateDescription, predicateKey);
}
Related
I know having a Unit Of Work is having an abstraction on top of an abstraction (DbContext) and surely that is an anti-pattern, or at least is not necessary.
I have the following problem:
I have a generic IRepository like so:
public interface IGenericRepository<TEntity> where TEntity : class
{
IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "");
TEntity GetByID(object id);
void Insert(TEntity entity);
void Delete(object id);
void Delete(TEntity entityToDelete);
void Update(TEntity entityToUpdate);
}
and this is the implementation of this interface:
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
internal GymHelperContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(GymHelperContext context)
{
this.context = context;
dbSet = context.Set<TEntity>();
}
public virtual IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
IQueryable<TEntity> query = dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
public virtual TEntity GetByID(object id)
{
return dbSet.Find(id);
}
public virtual void Insert(TEntity entity)
{
dbSet.Add(entity);
}
public virtual void Delete(object id)
{
TEntity entityToDelete = dbSet.Find(id);
Delete(entityToDelete);
}
public virtual void Delete(TEntity entityToDelete)
{
if (context.Entry(entityToDelete).State == EntityState.Detached)
{
dbSet.Attach(entityToDelete);
}
dbSet.Remove(entityToDelete);
}
public virtual void Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate);
context.Entry(entityToUpdate).State = EntityState.Modified;
}
}
I have a proyect called Facade that instantiates a Mapper and a UnitOfWork, like so:
public class MuscleFacade
{
private readonly UnitOfWork _unitOfWork = new UnitOfWork();
private readonly MuscleMapping _muscleMapping = new MuscleMapping();
public MuscleFacade()
{
}
public IEnumerable<MuscleViewModel> GetAllMuscles()
{
var source = _unitOfWork.MuscleRepository
.Get()
.ToList();
var result = source.Select(x => _muscleMapping.MuscleToModel(x));
return result;
}
public GymViewModel GetGymViewModel()
{
GymViewModel gymViewModel = new GymViewModel
{
ListOfMuscles = GetAllMuscles().ToList()
};
return gymViewModel;
}
}
The MuscleFacade class it's what I inject on my controller with Autofac, I inject an IMuscleFacade in its constructor.
Now the thing is, my MuscleTypeViewModel have a list of MuscleViewModel these models are mapped with their Domain classes counterparts, and in this particular case a MuscleType have many Muscle (Eg: Arm have bicep, tricep, etc) so I put navigational properties on each of them, like so:
public class MuscleType : IEntity
{
public int Id { get; set; }
[StringLength(100)]
public string MuscleTypeName { get; set; }
public ICollection<Muscle> Muscles { get; set; }
}
public class Muscle : IEntity
{
public int Id { get; set; }
[StringLength(100)]
public string MuscleName { get; set; }
public int MuscleTypeId { get; set; }
public MuscleType MuscleType { get; set; }
}
Now let's look at GetAllMuscles method in the Facade again:
public IEnumerable<MuscleViewModel> GetAllMuscles()
{
var source = _unitOfWork.MuscleRepository
.Get()
.ToList();
var result = source.Select(x => _muscleMapping.MuscleToModel(x));
return result;
}
What if I want to Eager-Load MuscleType, how can I change the Get() in order to receive and Expression of Func instead of a string?
You can define a helper class that contains your include definitions:
abstract class IncludeDefinition<TEntity>
{
public abstract IQueryable<TEntity> Include(IQueryable<TEntity> entities);
}
class IncludeDefinition<TEntity, TProperty> : IncludeDefinition<TEntity>
{
public IncludeDefinition(Expression<Func<TEntity, TProperty>> includeEx)
{
_includeEx = includeEx;
}
private readonly Expression<Func<TEntity, TProperty>> _includeEx;
public override IQueryable<TEntity> Include(IQueryable<TEntity> entities)
{
return entities.Include(_includeEx);
}
}
Then use the IncludeDefinition in your Get method
public IEnumerable<Muscle> Get(params IncludeDefinition<Muscle>[] includes)
{
IQueryable<Muscle> muscles = ...;
foreach (var item in includes)
{
muscles = item.Include(muscles);
}
return muscles.ToList();
}
And call the method
_unitOfWork.MuscleRepository
.Get(new IncludeDefinition<Muscle, MuscleType>(m => m.MuscleType));
// Include as many as you wish
_unitOfWork.MuscleRepository
.Get(new IncludeDefinition<Muscle, MuscleType>(m => m.MuscleType),
new IncludeDefinition<Muscle, SomeOtherRelatedEntity>(m => m.SomeOtherProperty));
Edit here comes some way to "just include" instead of writing complicated syntax.
Create a new interface IQueryRepository that supports Get without explicit includes and Include, derive IGenericRepository from this interface:
public interface IQueryRepository<TEntity>
where TEntity : class
{
IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null);
IQueryRepository<TEntity> Include<TProperty>(Expression<Func<TEntity, TProperty>> referenceExpression);
}
public interface IGenericRepository<TEntity> : IQueryRepository<TEntity>
where TEntity : class
{
IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
params IncludeDefinition<TEntity>[] include);
// other methods like GetByID, Add, Update...
}
Update the GenericRepository definition - it uses the approach with IncludeDefinition that I initially described and it returns a GenericQueryRepositoryHelper when Include is called.
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
internal DbSet<TEntity> dbSet;
public IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null)
{
return Get(filter, orderBy, new IncludeDefinition<TEntity>[0]);
}
public IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, params IncludeDefinition<TEntity>[] includes)
{
IQueryable<TEntity> query = dbSet;
foreach (var item in includes)
{
query = item.Include(query);
}
if (filter != null)
{
query = query.Where(filter);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
public IQueryRepository<TEntity> Include<TProperty>(Expression<Func<TEntity, TProperty>> referenceExpression)
{
return new GenericQueryRepositoryHelper<TEntity>(this, new IncludeDefinition<TEntity, TProperty>(referenceExpression));
}
// other methods like GetByID, Add, Update...
}
Implement the GenericQueryRepositoryHelper to store includes and apply them when Get is called
public class GenericQueryRepositoryHelper<TEntity> : IQueryRepository<TEntity>
where TEntity : class
{
private readonly IList<IncludeDefinition<TEntity>> _includeDefinitions;
private readonly IGenericRepository<TEntity> _repository;
internal GenericQueryRepositoryHelper(IGenericRepository<TEntity> repository, IncludeDefinition<TEntity> includeDefinition)
{
_repository = repository;
_includeDefinitions = new List<IncludeDefinition<TEntity>> { includeDefinition };
}
public IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null)
{
return _repository.Get(filter, orderBy, _includeDefinitions.ToArray());
}
public IQueryRepository<TEntity> Include<TProperty>(Expression<Func<TEntity, TProperty>> referenceExpression)
{
_includeDefinitions.Add(new IncludeDefinition<TEntity, TProperty>(referenceExpression));
return this;
}
}
Happy querying with includes:
var repo = new GenericRepository<Muscle>(...);
repo.Include(x => x.MuscleType)
.Include(x => x.MuscleType.Muscles)
.Get(x => x.MuscleName == "Test", x => x.OrderBy(m => m.MuscleName));
I am building out unit tests for a small app we need to build.
I have implemented the Repository / Unit Of Work pattern. My manager classes implement the unit of work pattern.
For a given interface:
public interface IUserManager
{
List<ApplicationUser> GetUsers(Expression<Func<ApplicationUser, bool>> filter = null);
ApplicationUser GetUser(Expression<Func<ApplicationUser, bool>> filter);
ApplicationUser AddUser(string username, List<string> environmentIds, bool isAdmin = false);
void DeleteUser(string username);
ApplicationUser UpdateUser(string id, List<string> environmentIds, bool isAdmin = false);
IList<string> GetUserRoles(string id);
}
I have implemented
public class UserManager : IUserManager
{
#region private fields
private readonly IRepository<ApplicationUser> _userRepository;
private readonly IRepository<Application> _applicationRepository;
private readonly IRepository<Role> _roleRepository;
private readonly IActiveDirectoryManager _activeDirectoryManager;
#endregion
#region ctor
public UserManager(AppDbContext context, IActiveDirectoryManager activeDirectoryManager)
{
_activeDirectoryManager = activeDirectoryManager;
_userRepository = new Repository<ApplicationUser>(context);
_applicationRepository = new Repository<Application>(context);
_roleRepository = new Repository<Role>(context);
}
#endregion
#region IUserManager
public ApplicationUser AddUser(string username, List<string> applicationIds, bool isAdmin = false)
{
//Get the environments in the list of environmentIds
var applications = _applicationRepository.Get(e => applicationIds.Contains(e.Id)).ToList();
//Get the user from AD
var user = _activeDirectoryManager.GetUser(username);
//set the Id
user.Id = Guid.NewGuid().ToString();
//add the environments to the user
applications.ForEach(x =>
{
user.Applications.Add(x);
});
//if the user is an admin - retrieve the role and add it to the user
if (isAdmin)
{
var role = _roleRepository.Get(r => r.Name == "admin").FirstOrDefault();
if (role != null)
{
user.Roles.Add(role);
}
}
//insert and save
_userRepository.Insert(user);
_userRepository.Save();
//return the user
return user;
}
//removed for brevity
}
My unit test class:
[TestClass]
public class UserManagerUnitTest
{
private readonly Mock<IActiveDirectoryManager> _adManager;
private readonly IUserManager _userManager;
private readonly Mock<IRepository<Application>> _applicationRepository;
private readonly Mock<IRepository<ApplicationUser>> _userRepository;
private readonly Mock<IRepository<Role>> _roleRepository;
public UserManagerUnitTest()
{
var context = new Mock<AppDbContext>();
_adManager = new Mock<IActiveDirectoryManager>();
_applicationRepository = new Mock<IRepository<Application>>();
_userRepository = new Mock<IRepository<ApplicationUser>>();
_roleRepository = new Mock<IRepository<Role>>();
_userManager = new UserManager(context.Object, _adManager.Object);
}
[TestMethod]
[TestCategory("AddUser"), TestCategory("Unit")]
public void AddUser_ValidNonAdmin_UserIsAdded()
{
#region Arrange
string username = "testUser";
List<string> applicationIds = new List<string>() {"1", "2", "3"};
_applicationRepository.Setup(x => x.Get(It.IsAny<Expression<Func<Application, bool>>>(),
It.IsAny<Func<IQueryable<Application>, IOrderedQueryable<Application>>>(), It.IsAny<string>()))
.Returns(new List<Application>());
_adManager.Setup(x => x.GetUser(It.IsAny<string>())).Returns(new ApplicationUser());
#endregion
#region Act
var result = _userManager.AddUser(username, applicationIds, false);
#endregion
#region Assert
Assert.IsNotNull(result);
Assert.IsFalse(result.IsAdmin);
#endregion
}
}
And finally the repository interface:
public interface IRepository<TEntity> where TEntity : class
{
IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity> , IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "");
TEntity GetById(object id);
void Insert(TEntity entity);
void Delete(object id);
void Delete(TEntity entityToDelete);
void Update(TEntity entityToUpdate);
void Save();
}
And implementation:
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
private readonly AppDbContext _context;
internal DbSet<TEntity> DbSet;
public Repository(AppDbContext context)
{
_context = context;
DbSet = _context.Set<TEntity>();
}
public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "")
{
IQueryable<TEntity> query = DbSet;
if (filter != null)
query = query.Where(filter);
foreach (var prop in includeProperties.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(prop);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
public virtual TEntity GetById(object id)
{
return DbSet.Find(id);
}
public virtual void Insert(TEntity entity)
{
DbSet.Add(entity);
}
public virtual void Delete(object id)
{
TEntity entityToDelete = DbSet.Find(id);
Delete(entityToDelete);
}
public void Get(Expression<Func<Application, bool>> expression, Func<IQueryable<Application>> func, IOrderedQueryable<Application> orderedQueryable)
{
throw new NotImplementedException();
}
public virtual void Delete(TEntity entityToDelete)
{
if (_context.Entry(entityToDelete).State == EntityState.Detached)
{
DbSet.Attach(entityToDelete);
}
DbSet.Remove(entityToDelete);
}
public virtual void Update(TEntity entityToUpdate)
{
DbSet.Attach(entityToUpdate);
_context.Entry(entityToUpdate).State = EntityState.Modified;
}
public void Save()
{
_context.SaveChanges();
}
}
my problem is in the mock IRepository<Application>
_applicationRepository.Setup(x => x.Get(It.IsAny<Expression<Func<Application, bool>>>(),
It.IsAny<Func<IQueryable<Application>, IOrderedQueryable<Application>>>(), It.IsAny<string>()))
.Returns(new List<Application>());
For some reason - actual method is being used versus the overridden proxy from Moq. When the test executes - I get a null reference on the Get method of the repository - specifically on the query = DbSet:
public Repository(AppDbContext context)
{
_context = context;
DbSet = _context.Set<TEntity>();
}
public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "")
{
IQueryable<TEntity> query = DbSet; **//null here because db should be** mocked
if (filter != null)
query = query.Where(filter);
I am trying to test just the UserManager implementation - not the repository implementation.
What would be the correct way to set this test up?
The issue is you are passing the AppDbContext in the constructor of UserManager, which makes it dependent on it. The class in turn is creating internal instances of the repositories, thus always using the concrete classes:
public UserManager(AppDbContext context, IActiveDirectoryManager activeDirectoryManager)
{
_activeDirectoryManager = activeDirectoryManager;
_userRepository = new Repository<ApplicationUser>(context);
_applicationRepository = new Repository<Application>(context);
_roleRepository = new Repository<Role>(context);
}
You should instead abstract out the creation of the repositories and modify the constructor so that it takes an instance based on the interfaces:
public UserManager(IRepository<ApplicationUser> userRepository, IRepository<Application> applicationRepository, IRepository<Role> roleRepository, IActiveDirectoryManager activeDirectoryManager)
{
_activeDirectoryManager = activeDirectoryManager;
_userRepository = userRepository;
_applicationRepository = applicationRepository;
_roleRepository = roleRepository;
}
This way you are able to abstract out the repositories so your mocks are used instead of the real classes.
I have a RepositoryBase class that does some basic operations on Entities which are derived from EntityBase.
public class RepositoryBase
{
private ApplicationDbContext _context;
public DbSet<EntityBase> DbSet;
public RepositoryBase(ApplicationDbContext context )
{
_context = context;
}
public List<EntityBase> List(int entityStatus)
{
return DbSet.Where(a => a.EntityStatusId == entityStatus).OrderBy(a => a.Name).ToList();
}
public EntityBase GetTeamDetails(int id)
{
return this.DbSet.FirstOrDefault(a => a.Id == id);
}
internal List<EntityBase> ListActive()
{
return DbSet.Where(a => a.EntityStatusId == (int)EntityStatus.Active).ToList();
}
internal List<EntityBase> ListTrashed()
{
return DbSet.Where(a => a.EntityStatusId == (int)EntityStatus.Trashed).ToList();
}
public void SaveProject(EntityBase item)
{
DbSet.Attach(item);
_context.Entry(item).State = EntityState.Modified;
_context.SaveChanges();
}
public List<EntityBase> ListArchived()
{
return DbSet.Where(a => a.EntityStatusId == (int)EntityStatus.Archived).ToList();
}
internal List<EntityBase> Search(string searchText)
{
return DbSet.Where(a => a.Name.Contains(searchText)).ToList();
}
public EntityBase New(EntityBase item)
{
DbSet.Add(item);
_context.SaveChanges();
return item;
}
}
The issue I am having is passing the DbSet to the base class. This is what I want to do:
public TeamRepository(ApplicationDbContext context) : base(context)
{
this.DbSet = (DbSet<EntityBase>)context.Teams;
}
However, this does not compile. It says it cannot cast from DbSet to DbSet even through Team is derived from EntityBase.
How do I make this cast?
you can make it generic this way:
public class BaseRepository<T> : IBaseRepository<T> where T : EntityBase
{
public BaseRepository(CustomDBContext context)
{
if (context == null)
{
throw new ArgumentNullException("context", "The given parameter cannot be null.");
}
this.Context = context;
}
protected ApplicationDbContext Context
{
get;
private set;
}
public T Get(int id)
{
return Context.Set<T>().Find(id);
}
.....
}
You can't do it like that. What you can do is:
this.DbSet = context.Set<EntityBase>();
I am mocking a DbContext for unit testing, and when you save changes in your database the instances you added pull the new id assigned by the database identity column, is there any way to mock this behavior?, I really have no clue where to start.
var acc = new Account {Name = "A New Account"};
_db.Accounts.Add(acc);
_db.SaveChanges();
Assert.IsTrue(acc.Id > 0);
Where
public class TestDbContext : IEntities
{
public DbSet<Instance> Accounts { get; set; } = new MockDbSet<Accounts>();
}
And
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
namespace ControliApiTests.Data
{
public class MockDbSet<T> : DbSet<T>, IQueryable, IEnumerable<T> where T : class
{
readonly ObservableCollection<T> _data;
readonly IQueryable _queryable;
public MockDbSet()
{
_data = new ObservableCollection<T>();
_queryable = _data.AsQueryable();
}
public virtual T Find(params object[] keyValues)
{
throw new NotImplementedException("Derive from MockDbSet<T> and override Find");
}
public Task<T> FindAsync(CancellationToken cancellationToken, params object[] keyValues)
{
throw new NotImplementedException();
}
public override T Add(T item)
{
_data.Add(item);
return item;
}
public override IEnumerable<T> AddRange(IEnumerable<T> entities)
{
var addRange = entities as T[] ?? entities.ToArray();
foreach (var entity in addRange)
{
_data.Add(entity);
}
return addRange;
}
public override T Remove(T item)
{
_data.Remove(item);
return item;
}
public override T Attach(T item)
{
_data.Add(item);
return item;
}
public override T Create()
{
return Activator.CreateInstance<T>();
}
public override TDerivedEntity Create<TDerivedEntity>()
{
return Activator.CreateInstance<TDerivedEntity>();
}
public override ObservableCollection<T> Local
{
get { return _data; }
}
Type IQueryable.ElementType
{
get { return _queryable.ElementType; }
}
System.Linq.Expressions.Expression IQueryable.Expression
{
get { return _queryable.Expression; }
}
IQueryProvider IQueryable.Provider
{
get { return new AsyncQueryProviderWrapper<T>(_queryable.Provider); }
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return _data.GetEnumerator();
}
}
internal class AsyncQueryProviderWrapper<T> : IDbAsyncQueryProvider
{
private readonly IQueryProvider _inner;
internal AsyncQueryProviderWrapper(IQueryProvider inner)
{
_inner = inner;
}
public IQueryable CreateQuery(Expression expression)
{
return new AsyncEnumerableQuery<T>(expression);
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new AsyncEnumerableQuery<TElement>(expression);
}
public object Execute(Expression expression)
{
return _inner.Execute(expression);
}
public TResult Execute<TResult>(Expression expression)
{
return _inner.Execute<TResult>(expression);
}
public Task<object> ExecuteAsync(Expression expression, CancellationToken cancellationToken)
{
return Task.FromResult(Execute(expression));
}
public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
{
return Task.FromResult(Execute<TResult>(expression));
}
}
public class AsyncEnumerableQuery<T> : EnumerableQuery<T>, IDbAsyncEnumerable<T>
{
public AsyncEnumerableQuery(IEnumerable<T> enumerable) : base(enumerable)
{
}
public AsyncEnumerableQuery(Expression expression) : base(expression)
{
}
public IDbAsyncEnumerator<T> GetAsyncEnumerator()
{
return new AsyncEnumeratorWrapper<T>(this.AsEnumerable().GetEnumerator());
}
IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator()
{
return GetAsyncEnumerator();
}
}
public class AsyncEnumeratorWrapper<T> : IDbAsyncEnumerator<T>
{
private readonly IEnumerator<T> _inner;
public AsyncEnumeratorWrapper(IEnumerator<T> inner)
{
_inner = inner;
}
public void Dispose()
{
_inner.Dispose();
}
public Task<bool> MoveNextAsync(CancellationToken cancellationToken)
{
return Task.FromResult(_inner.MoveNext());
}
public T Current
{
get { return _inner.Current; }
}
object IDbAsyncEnumerator.Current
{
get { return Current; }
}
}
}
If you define
private static int IdentityCounter = 1;
in your mock implementation and increment it by one for each added item, you will get an incrementing value that does not reset as long as the app domain exists.
If your tests allow for multi-threaded adds, use Interlocked.Increment to update the counter.
Note that your current implementation does not demand that an object have an Id property. If all of the classes in the test have such a property, you can define an interface to use rather than allowing anything that is class.
public interface DbEntity
{
int Id { get; set; }
}
public class MockDbSet<T> : DbSet<T>, IQueryable, IEnumerable<T> where T : DbEntity
With that change, your implementation of Add could look like
public override T Add(T item)
{
item.Id = IdentityCounter++; // Or use Interlocked.Increment to support multithreading
_data.Add(item);
return item;
}
If you don't want use a interface can use reflection and extension method for take and evaluate the id
var MockSet = new Mock<DbSet<T>>();
MockSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(MockData.AsQueryable().Provider);
MockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(MockData.AsQueryable().Expression);
MockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(MockData.AsQueryable().ElementType);
MockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => MockData.AsQueryable().GetEnumerator());
MockSet.Setup(m => m.Add(It.IsAny<T>())).Callback<T>(MockData.AddPlus); // here change te method 'Add' for the extension method 'AddPlus'
public static void AddPlus<T>(this List<T> miLista, T item)
{
int nuevoId;
int? id;
try
{
id = (int)item.GetPropValue("id");
}
catch
{
id = null;
}
if (id == 0)
{
if (miLista.Count() > 0)
{
var listaInts = miLista.Select(i => (int)i.GetPropValue("id"));
nuevoId = listaInts.Max(x=>x) + 1;
}
else
nuevoId = 1;
item.SetPropValue("id",nuevoId);
}
miLista.Add(item);
}
is it possible?
Public String Get_Filed_By_Id(string table_Name,String Field_Name,string PK_val)
{
string strRes="";
using(mydbcontext db=new mydbcontext())
{
var x=db.table_Name.Where(p=>p.Id=PK_val).FirstOrDefault().Field_Name;
strRes=Convert.Tostring(x);
}
return strRes;
}
OR
var x=(from o in db.table_Name where o.Id=PK_val select o.Field_Name).FirstOrDefault();
Here, i'm passing Table_Name,Column_Name and the Condition value(PK_val) to Get the Column_Name from Table_Name within a Certain Condition(Id=Pk_val).
Is it possible??
Is it possible??
Yes, it is.
First, some helpers:
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace YourNamespace
{
internal static class DbHelpers
{
public static object GetColumnById(this object dbContext, string tableName, string columnName, object id)
{
var table = (IQueryable)dbContext.GetType().GetProperty(tableName).GetValue(dbContext, null);
var row = Expression.Parameter(table.ElementType, "row");
var filter = Expression.Lambda(Expression.Equal(Expression.Property(row, "Id"), Expression.Constant(id)), row);
var column = Expression.Property(row, columnName);
var selector = Expression.Lambda(column, row);
var query = Call(Where.MakeGenericMethod(row.Type), table, filter);
query = Call(Select.MakeGenericMethod(row.Type, column.Type), query, selector);
var value = Call(FirstOrDefault.MakeGenericMethod(column.Type), query);
return value;
}
private static readonly MethodInfo Select = GetGenericMethodDefinition<
Func<IQueryable<object>, Expression<Func<object, object>>, IQueryable<object>>>((source, selector) =>
Queryable.Select(source, selector));
private static readonly MethodInfo Where = GetGenericMethodDefinition<
Func<IQueryable<object>, Expression<Func<object, bool>>, object>>((source, predicate) =>
Queryable.Where(source, predicate));
private static readonly MethodInfo FirstOrDefault = GetGenericMethodDefinition<
Func<IQueryable<object>, object>>(source =>
Queryable.FirstOrDefault(source));
private static MethodInfo GetGenericMethodDefinition<TDelegate>(Expression<TDelegate> e)
{
return ((MethodCallExpression)e.Body).Method.GetGenericMethodDefinition();
}
private static object Call(MethodInfo method, params object[] parameters)
{
return method.Invoke(null, parameters);
}
}
}
and now your function:
public string Get_Field_By_Id(string table_Name, string field_Name, string PK_val)
{
using (var db = new mydbcontext())
return Convert.ToString(db.GetColumnById(table_Name, field_Name, PK_val));
}
It is not really possible with EntityFramework actually(as far as I know). If you only needed the field by its name, then you could have used #Den's proposed solution. But you want to specify the table name too as a parameter. So I suggest you to use standard Sql Connector api, and build the query string with the parameters you provide.
Check this link for usage of standard sql connector api.
I had this question too ,I know this is not exactly what you want and you need write more code but it's much cleaner than those you want to write.
Using repository pattern
For every table you should have a model class and Repository class.
Consider this code(this code from one of my project)
This is my comment table(this can be anything with or without navigation property)
public sealed class Comment
{
public string CommentText { get; set; }
public DateTime PostDate { get; set; }
public int PostId { get; set; }
public int? PageId { get; set; }
public Page Page { get; set; }
public User User { get; set; }
public string UserId { get; set; }
public int? ParentId { get; set; }
public Comment[] ChildComments { get; set; }
}
RepositoryComment
public sealed class CommentRepository : BaseRepository<Comment>
{
public CommentRepository(BabySitterContext context)
: base(context)
{
}
}
and a base class that you send your query with table name(here model) and field(you can extend clas for more functionality)
public class BaseRepository<T> where T : class
{
protected BabySitterContext Context;
private readonly PluralizationService _pluralizer = PluralizationService.CreateService(CultureInfo.GetCultureInfo("en"));
public BaseRepository(BabySitterContext context)
{
this.Context = context;
}
public bool Add(T t)
{
Context.Set<T>().Add(t);
Context.SaveChanges();
return true;
}
public bool Update(T t)
{
var entityName = GetEntityName<T>();
object originalItem;
var key = ((IObjectContextAdapter)Context).ObjectContext.CreateEntityKey(entityName, t);
if (((IObjectContextAdapter)Context).ObjectContext.TryGetObjectByKey(key, out originalItem))
{
((IObjectContextAdapter)Context).ObjectContext.ApplyCurrentValues(key.EntitySetName, t);
}
Context.SaveChanges();
return true;
}
public void Attach(T t)
{
if (t == null)
{
throw new ArgumentNullException("t");
}
Context.Set<T>().Attach(t);
Context.SaveChanges();
}
public void Remove(T t)
{
if (t == null)
{
throw new ArgumentNullException("t");
}
Context.Set<T>().Remove(t);
Context.SaveChanges();
}
public IEnumerable<T> Get(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = "")
{
IQueryable<T> query = Context.Set<T>();
if (filter != null)
{
query = query.Where(filter.Expand());
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
private string GetEntityName<TEntity>() where TEntity : class
{
return string.Format("{0}.{1}", ((IObjectContextAdapter)Context).ObjectContext.DefaultContainerName, _pluralizer.Pluralize(typeof(TEntity).Name));
}
public virtual IEnumerable<T> GetByBusinessKey(T entity)
{
return null;
}
}
For any other table just make model class and reposiotry then inherite from base class
Using code
var context = new BabySitterContext();
var _commentRepository = new CommentRepository(context);
var comment = _commentRepository.Get(x => x.PostId == id).FirstOrDefault();
No, but in this way
Public String Get_Filed_By_Id(string table_Name,String Field_Name,string PK_val)
{
string strRes="";
using(mydbcontext db=new mydbcontext())
{
var x=db.table_Name.Where(p=>p.Id=PK_val).Select(b=>b.Field_Name).FirstOrDefault();
strRes=Convert.Tostring(x);
}
return strRes;
}