get name of table in repository design pattern - c#

I am working in project using generic repository design pattern and i need to get the name of entity(name of table) that sent to the following Add function
public class Repository<TEntity> : IRepository<TEntity> where TEntity:class
{
public TEntity Add(TEntity entity)
{
validate("nameoftable");
TEntity result= _set.Add(entity);
return result;
}
private validate(string entity-name)
{
if (entity-name == "students")
{
////do some work
}
}
i want to get the entity table to use it for some validation before save

Why can't you say like below if TEntity happens to be the entity or table name
validate(typeof(TEntity).FullName);
(OR)
validate(typeof(TEntity).Name);

Related

Return a list from Entity Framework, based on string parameter

I have a database first Entity Framework setup. Usually, I create procedures like this, to return a list of a defined object in my model.
public List<Employees> GetEmployees()
{
var tables = _crmContext.Employees.ToList();
return tables;
}
That works fine but the case I can't figure out, it different. I want to return a list of an object in the entity framework model, based on a parameter passed to the procedure.
I was trying something like this, but it's not working and I also don't know if is the right approach.
public List<T> GetValuesFromTable(string table)
{
var results = _crmContext."table".ToList();
return results;
}
Thanks for the help.
I think the Generic Repository Pattern is what you're looking for. In this way, you can call all the tables you have given type with a single method. Example
Repository.cs
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected readonly DbContext Context;
public Repository(DbContext context)
{
this.Context = context;
}
public IEnumerable<TEntity> GetAll()
{
return Context.Set<TEntity>().ToList();
}
}
IRepository.cs
public interface IRepository<TEntity> where TEntity : class
{
IEnumerable<TEntity>GetAll();
}

Remove an entity without fetching it in the generic repository pattern entity framework

I am trying to delete an entity of Employee from the database which contains different tables like Employee, Project, Skills using a generic repository pattern.
namespace Information.Repository
{
public class IRepositoy<TEntity> : IRepository<TEntity> where TEntity : class
{
private readonly ApplicationDbContext _dbContext;
public IRepositoy(ApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public void Remove(int id)
{
TEntity element = _dbContext.Set<TEntity>().Find(id);
_dbContext.Set<TEntity>().Remove(element);
}
}
}
When the above Remove method is called it makes two database call
One for getting the entity.
Second for deleting it.
I have found the query like the below one which executes with single SQL query
when the entity type(Employee or Project or Skill) is known
public void Remove(int id)
{
Employee employee = new Employee { EmployeeId = id };
_dbContext.Entry(employee).State = EntityState.Deleted;
}
can anyone please suggest me how to delete an entity without fetching it using a generic repository pattern similar to the above example.
Using raw SQL
Entity Framework doesn't allow you to delete an object that you haven't loaded (or attached). This also extends to conditional deletes (e.g. deleting all users named John) as it requires you to load the users before deleting them.
You can get around this by executing raw SQL. It's not ideal as you tend to use EF so you don't have to write SQL, but the lack of a decent delete behavior (without loading) makes this an acceptable solution.
Something along the lines of:
using (var context = new FooContext())
{
var command = "DELETE * FROM dbo.Foos WHERE Id = 1";
context
.Database
.ExecuteSqlCommand(command);
}
Where relevant, don't forget about SQL injection protection. However, it's usually a non-issue for simple deletes as the FK is usually a GUID or int, which doesn't expose you to injection attacks.
Making it generic
The example you posted works as well, but you're probably not using it because it can't easily be made generic-friendly.
What I tend to do in all my EF projects is to have an (abstract) base class for all my entities, something along the lines of:
public class BaseEntity
{
public int Id { get; set; }
public DateTime CreatedOn { get; set; }
public string CreatedBy { get; set; }
public DateTime? UpdatedOn { get; set; }
public string UpdatedBy { get; set; }
}
An interface would also work, I just prefer a base class here.
The audit fields are not part of this answer but they do showcase the benefits of having a base class.
When all your entities inherit from the same base class, you can put a generic type constraint on your repositories which ensures that the generic type has an Id property:
public class IRepositoy<TEntity> : IRepository<TEntity> where TEntity : BaseEntity
At which point you can generically implement your proposed solution:
public void Remove(TEntity obj)
{
dbContext.Entry(obj).State = EntityState.Deleted;
}
You can also specify a parameterless constructor type constraint:
where TEntity : BaseEntity, new()
which enables you to instantiate your generic type as well:
public void Remove(int id)
{
TEntity obj = new TEntity() { Id = id };
dbContext.Entry(obj).State = EntityState.Deleted;
}
Note
There is a generic raw SQL solution as well, but I've omitted it as it is more complex because it requires you to retrieve the table name based on the entity type.
The raw SQL variant is only valuable in cases where you want to execute conditional deletes (e.g. removing all entities whose id is an even number).
However, since most conditional deletes are entity-specific, this means that you generally don't need to make them generic, which makes the raw SQL approach more viable as you only have to implement it in a specific repository and not the generic one.
You still have to fetch it. Entity Framework caches your dbSets so it's usually pretty quick. Use the same context like so:
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);
}
Where dbSet =
context.Set<TEntity>();
The current limitation of Entity Framework is, in order to update or delete an entity you have to first retrieve it into memory. However there are few alternatives to delete a specific record.
You can try ExecuteSqlCommandto delete a specific record
_dbContext.Database.ExecuteSqlCommand("Delete Employee where EmployeeId = {0}", id );
or try using EntityFramework.Extended Library to delete a specific record
_dbContext.Settings.Where(s=> s.EmployeeId == id).Delete();

Entity Framework and Repository Pattern conceptual difficulties

I am making an intranet website using ASP.NET MVC and SQL Server 2012. I am making a repository and architecturing with Onion Architecture. My problem is that the company in which I am working, already has several Server DBs in which the tables have no relations between each other. Instead, there are tables to map these relations. For example a table User, and a table Document have a table User_joint_Document to make a relation, containing both IDs (IDDocument and IDUser). Now when I write my generic repository:
class Repository<T> : IRepository<T> where T : class
the problem is the Generic type T makes no sense and I can't affect values in my model using EF queries which is normal, and what would be great would be to have a parent class BaseEntity to have IDs defined for each tables, then I can write:
class Repository<T> : IRepository<T> where T : BaseEntity
And all my table models would inherit from BaseEntity. But that would also mean rewriting the whole DB in a relational manner and mapping every DB POCO manually(correct me if I'm wrong), and I do not have the skillset to do this(there are over 300 tables in the different server DBs and I lack proper knowledge and experience to do this kind of operation).
Is there a way to keep my original DB structure, and still write a Generic Repository? How would one go about doing this?
EDIT To clarify my question because #saeb answered partially to my question. Can I have a generic repo without having a parent class for my DB POCOs? Or do I need it in order to then have only ONE repository to rule them all? For example:
class Repository<T>:IRepository<T> where T : class
{
private readonly ApplicationContext context;
private DbSet<T> entities;
public Repository(PrincipalServerContext context)
{
this.context = context;
entities = context.Set<T>();
}
public T Get(long id)
{
return entities.SingleOrDefault(s => s.IDUser == id);
//This does not work, IDUser isn't recognized
}
Thanks for your help!
... has several Server DBs in which the tables have no relations between each other ...
But they do have a relationship, a Many-to-Many relationship, which is defined via that third mapping table (whether that's a correctly defined relationship is another topic)
... the problem is the Generic type T makes no sense and I can't affect values in my model using EF queries ...
Why doesn't it and why can't you? considering your table examples, you'd have two entities, User and Document and they'd look like this:
public class User
{
public int IDUser { get; set; }
public virtual ICollection<Document> Documents { get; set; }
...
}
public class Document
{
public int IDDocument { get; set; }
public virtual ICollection<User> Users { get; set; }
...
}
And you can use the fluent API in your context's OnModelCreating to set up the relationship via the third table:
public class YourContext: DbContext
{
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasMany<Document>(u => u.Documents)
.WithMany(d => d.Users)
.Map(userJointDocument =>
{
userJointDocument.MapLeftKey("IDUser");
userJointDocument.MapRightKey("IDDocument");
userJointDocument.ToTable("User_joint_Document");
});
}
...
}
And then you can query Users and Documents in your repository as you would if there was a direct relationship between them. Here are more good sources to learn more about this if you like.
As far as I can see your problem, there is now way of achieving this without putting at least a base class or an interface to your entities/POCOs
You can play around with expressions for achieving a generic Repository
public interface IEntity<T> where T : class
{
Expression<Func<T, bool>> GetByIdPredicate(long id);
}
public partial class User : IEntity<User>
{
public int UserID { get; set; }
public Expression<Func<User, bool>> GetByIdPredicate(long id)
{
return (User entity) => entity.UserID == id;
}
}
class Repository<T>:IRepository<T> where T : class, IEntity, new()
{
private readonly ApplicationContext context;
private DbSet<T> entities;
T dummyEntity;
public Repository(PrincipalServerContext context)
{
this.context = context;
entities = context.Set<T>();
dummyEntity = new T();
}
public T Get(long id)
{
return entities.SingleOrDefault(dummyEntity.GetByIdPredicate(id));
}
There's probably a cleaner way that also gets rid of the dummyEntity field

Can we use Generic Repository without using EF? Is it a good practise?

I have an application in which the person who designed the application had used a dbml to manage db classes. But we have another database that we often need to connect to and we've been using ado.net normally to connect to it as we cannot use same dbml for it. However, I do not personally like using a LINQ database as the generated auto-code causes errors whenever we add a new table or property.
I've been trying to implement a repository pattern with self-declared classes to map to each table but to manage operations on each table, we need a separate repository for each entity. I'm not sure if I'm on the right path using this pattern but if I'm not using EF in this case, can we have a generic repository to represent the general operations or just create separate repository for each entity that we create?
Also, for generic repository, I would appreciate if I can get some example or pointers to it.
Sorry if I sound redundant.
Thanks in advance!
Generic repository is a good idea if you will just use CRUD operations, (Create, Read, Update and Delete)
for me, i don't like much the to generate the database entities through DBML, i usually write entities and their mappings manually , here under some example of a project i am working on
first the model
public class Operator
{
public virtual string OperatorName { get; set; }
public virtual string LoginName { get; set; }
public virtual string Email { get; set; }
public virtual string PhoneNo { get; set; }
public virtual short Status { get; set; }
public virtual byte[] Password { get; set; }
}
UPDATE :
to make the repository independent of the provider you should define custom context which the repository will use
first define the interface
public interface IGenericContext
{
void Add<T>(T entity)
where T : class;
void Update<T>(T entity)
where T : class;
void Delete<T>(T entity)
where T : class;
IQueryable<T> GetIQueryable<T>()
where T : class;
}
here a sample of EF context that implements the IGenericContext interface
public class EFContext : DbContext, IGenericContext
{
public EFContext(string connectionName)
: base(connectionName)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.AddFromAssembly(this.GetType().Assembly);
base.OnModelCreating(modelBuilder);
}
public void Add<T>(T entity) where T : class
{
this.Set<T>().Add(entity);
this.SaveChanges();
}
public void Update<T>(T entity) where T : class
{
this.Set<T>().Attach(entity);
this.Entry(entity).State = EntityState.Modified;
this.SaveChanges();
}
public void Delete<T>(T entity) where T : class
{
this.Set<T>().Attach(entity);
this.Set<T>().Remove(entity);
this.SaveChanges();
}
public IQueryable<T> GetIQueryable<T>() where T : class
{
return this.Set<T>();
}
}
for EF, you will need to do the mappings yourself like below
public class OperatorMapping : EntityTypeConfiguration<Operator>
{
public OperatorMapping()
{
this.ToTable("Operators");
this.Property(t => t.OperatorName).IsRequired().HasColumnName("OperatorName");
this.HasKey(t => t.LoginName).Property(t => t.LoginName).HasColumnName("LoginName");
this.Property(t => t.Email).IsRequired().HasColumnName("Email");
this.Property(t => t.PhoneNo).HasColumnName("PhoneNo");
this.Property(t => t.Status).IsRequired().HasColumnName("Status");
this.Property(t => t.Password).IsRequired().HasColumnName("Password");
}
}
then a generic repository, this repository will use the IGenericContext instead of working on EF DBContext
public class Repository<TEntity>
where TEntity : class, new()
{
protected IGenericContext Context { get; set; }
public Repository(IGenericContext context)
{
Context = context;
}
public void Add(TEntity entity)
{
Context.Add(entity);
}
public void Update(TEntity entity)
{
Context.Update(entity);
}
public void Delete(TEntity entity)
{
Context.Delete(entity);
}
public List<TEntity> ToList()
{
return Context.GetIQueryable<TEntity>().ToList();
}
}
all you need to do is create the DBContext, pass it to the generic repository and do your operations
IGenericContext context = new EFContext("Infrastructure");
Repository<Operator> repository = new Repository<Operator>(context);
var operators = repository.ToList();
you can then implement another context that do the basic CRUD operations and still can use the same repository

Generic Repository & Entity Framework Logic to Retrieve Entity with Includes

I have two Entity Framework 5 Get() methods that perform (i) a single entity get by ID, and (ii) a single entity get via a filter with any eager loading bolted on. See below for the code:
internal readonly FallenNovaContext Context;
private readonly DbSet<TEntity> _dbSet;
internal GenericRepository(FallenNovaContext context)
{
Context = context;
_dbSet = context.Set<TEntity>();
}
// (i) Get by ID.
public TEntity GetById(int id)
{
return _dbSet.Find(id);
}
// (ii) Get by filter and optional eager loading includes.
public TEntity Get(
Expression<Func<TEntity, bool>> filter = null,
IEnumerable<string> includePaths = null)
{
IQueryable<TEntity> query = _dbSet;
if (filter != null)
{
query = query.Where(filter);
}
if (includePaths != null)
{
query = includePaths.Aggregate(query, (current, includePath) => current.Include(includePath));
}
return query.SingleOrDefault();
}
All of which works fine now what I'm finding as my application grows is I'm writing a lot of non-generic methods that need a mix of both - more specifically I want a generic get by ID and also be able to eager load related entities.
So the method signature would look something like this:
public TEntity GetById(
int id,
IEnumerable<string> includePaths)
{
// ???
}
Which I could call like this:
User user = UnitOfWork.UserRepository.GetById(117, new List<string>() { "UserRole", "UserStatus" });
Or like this:
Car car = UnitOfWork.CarRepository.GetById(51, new List<string>() { "Make", "Model", "Tyres" });
Any help on the suggestions of how I use Entity Framework 5 to code the logic for the TEntity GetById(int id, IEnumerable includePaths) method would be appreciated.
First, write a base class for entities, which defines the primary key field. Something like the following may work:
public abstract class BaseEntity
{
public int Id {get;set;}
}
Then, write a base class for your repositories; define all generic methods in this base repository. Let this repository have a generic parameter of entity type:
public class RepositoryBase<TEntity> where TEntity : BaseEntity
{
public TEntity GetById(
int id,
params Expression<Func<TEntity, object>>[] includeList)
{
TEntity entity = null;
ObjectQuery<TEntity> itemWithIncludes = context.Set<TEntity>() as ObjectQuery<TEntity>;
foreach (Expression<Func<TEntity, object>> path in includeList)
{
itemWithIncludes = ((IQueryable)itemWithIncludes.Include(path)) as ObjectQuery<T>;
}
IQueryable<TEntity> items = itemWithIncludes.AsQueryable<TEntity>();
entity = items.Where(p => p.Id == id).SingleOrDefault();
return entity;
}
}
Update: #Bern asked whether there is any other way to find primary key than declaring a base class. The following questions refer to this problem.
Entity Framework 4: How to find the primary key?
Entity Framework code first. Find primary key
On the otherhand I do not know if there is any other way in EF 5.

Categories