generic function to search a value in a table, with multiple DBcontexts - c#

I have the following search function for the search for duplicate values
public bool isRecordExisting(string newValue)
{
bool isExisting = false;
using (var db = new SampleEntities_1())
{
var res = db.SAMPLE_TABLE.Where(x => x.SAMPLE_COLUMN == newValue).First();
if (res != null) {
isExisting = false;
}
}
return isExisting;
}
I got a few DbInstances
SampleEntities_1
SampleEntities_2
SampleEntities_3
Therefore I trying to make this function a generic one, like following
public bool isRecordExisting(string newValue, string column, DbSet<T> tableName, DbContext dbcontextname)
{
bool isExisting = false;
using (var db = new dbcontextname())
{
var res = db.tableName.Where(x=>x.column = newValue).First();
if (res != null)
{
isExisting = false;
}
}
return isExisting;
}
so I can call this function like this
var result = isRecordExisting("Bob", "SAMPLE_COLUMN", "SAMPLE_TABLE", SampleEntities_1);
can I know this approach possible or not, already I have compilation errors :(
'dbcontextname' is a variable but is used like a type
'SampleEntities_1' is a type, which is not valid in the given context

You could use a Generic repository, or a factory type pattern, etc..
Example, if you want to create a Generic Repository in your case, then something like this:
public class GenericRepo<TEntity, TContext> : IGenericRepo<TEntity>, IDisposable where TEntity : class where TContext : DbCOntext, new()
{
public TContext Context;
public GenericRepo(DbContext)
{
Context = dbContext as TContext;
}
public virtual TEntity Get(Expression<Func<TEntity, bool>> where = null)
{
Context.Set<TEntity>.FirstOrDefault(where);
}
}
Then maybe something like this:
public bool isRecordExisting(string newValue, string column)
{
bool isExisting = false;
using (var db = new GenericRepo<EntityType, SampleEntities_1>())
{
var res = db.Get(x => x.column == newValue);
if (res != null)
{
isExisting = false;
}
}
return isExisting;
}
Although you can pass the column and tablename essentially this way ^, you still need to create an instance of the GenericRepo for each DBContext. Same with the factory pattern. You could try what Salomon Zhang mentioned in the comments.
Also, note: Always use async code for accessing the DB.

Related

Returning a generic type without T at compile time

I have a list of generics defined like so:
class Registrations
{
private readonly List<MetaRegistration> _registrations = new List<MetaRegistration>();
private abstract class MetaRegistration
{
}
private class Registration<T> : MetaRegistration
{
public async Task<T> Resolve(string value)
{
return await ...
}
}
}
And I'd like to run a method on one of the Registration<T> instances.
I can easily do it like this if I know the type at compile time:
public async Task<T> Resolve<T>(string value)
{
var registration = _registrations.Cast<Registration<T>>()
.First(r => r.GetType().GenericTypeArguments[0] == typeof(T));
var model = await registration.Resolve(value);
return model;
}
But how would I go about this without when I don't know T?
Right now, this is how I've come around the problem using reflection, where I know the Type, but only during runtime:
public async Task<object?> Resolve(Type type, string value)
{
foreach (var metaRegistration in _registrations)
{
Type t = metaRegistration.GetType();
if (!t.IsGenericType || t.GetGenericTypeDefinition() != typeof(Registration<>) ||
t.GenericTypeArguments[0] != type) continue;
var methodInfo = metaRegistration.GetType().GetMethod("Resolve");
var task = (Task) methodInfo?.Invoke(metaRegistration, new object?[] {value})!;
await task;
return task.GetType().GetProperty("Result")?.GetValue(task);
}
return null;
}
However, I would prefer to avoid reflection together, and this feels like I'm doing something incorrectly.
Is there any other way to go about this?

Use type derived from GetType() without using Switch

I am using Entity Framework and LINQ. I want to create a reusable method in a "helper" class for GridViews.
The method will return a DataSource as a List of entities based off the type of entity passed.
So GridView1 will show [Entity1]'s so the call will look like:
GridView1.DataSource = helperClass.GetDataSource(new Entity1());
Note* If I should pass the entity type I want as a string in the method I am open for suggestion. I just don't want to have to use a switch case between the ~40 entity types this method could return
The reusable method will be simple and look similar to:
public static object GetDataSource(object type)
{
using (DatabaseContext dc = new DatabaseContext())
{
if (dc.[how do I get the entity type here].Count() > 0)
{
var modelList = dc.[how do I get the entity type here also].ToList();
}
}
}
This will sound silly, but obviously I wasn't able to do:
var modelList = dc.(type.GetType()).ToList();
but that is basically what I want to accomplish.
If you want to bind the type at compile-time, you can pass the type as a generic argument, and use this type of method:
public DbSet<T> GetDataSource<T>()
{
var targetType = typeof(DbSet<T>);
return _db
.GetType()
.GetMethods()
.Where( m => m.ReturnType == targetType)
.Single()
.Invoke(_db, null) as DbSet<T>;
}
How does it work? Well, we don't know the name of the method that returns the entity that is being requested, but we do know that the return type has to be a DbSet<T>. So we scan the DatabaseContext for any method that returns that type, and invoke it. This assumes there is exactly one method that has that return type.
If you need true run-time binding (you can't supply the <T> parameter) you can use this sort of method. Note that the return type is just a general IEnumerable because you can't have a specific return type if it's not known at compile time. You can always cast it back to a DbSet<T> if needed.
public IEnumerable GetDataSource(Type type)
{
var targetType = typeof(DbSet<>).MakeGenericType(new Type[] { type });
return _db
.GetType()
.GetMethods()
.Where( m => m.ReturnType == targetType)
.Single()
.Invoke(_db, null) as IEnumerable;
}
Here is a full example. Note that I stubbed out the EF objects, but this example should still work with a real DbSet and DatabaseContext.
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
public class Program
{
public class DbSet<T> : List<T>
{
}
public class User
{
public string Name { get; set; }
public override string ToString()
{
return "User " + Name;
}
}
public class Transaction
{
public decimal Amount { get; set; }
public override string ToString()
{
return "Transaction " + Amount.ToString("0.00");
}
}
public class DatabaseContext
{
public DbSet<User> GetUsers()
{
return new DbSet<User>()
{
new User { Name = "Bob" },
new User { Name = "Alice" }
};
}
public DbSet<Transaction> GetTransactions()
{
return new DbSet<Transaction>()
{
new Transaction { Amount = 12.34M },
new Transaction { Amount = 56.78M }
};
}
}
public class HelperClass
{
private readonly DatabaseContext _db;
public HelperClass(DatabaseContext db)
{
_db = db;
}
public DbSet<T> GetDataSource<T>()
{
var targetType = typeof(DbSet<T>);
return _db
.GetType()
.GetMethods()
.Where( m => m.ReturnType == targetType)
.Single()
.Invoke(_db, null) as DbSet<T>;
}
public IEnumerable GetDataSource(Type type)
{
var targetType = typeof(DbSet<>).MakeGenericType(new Type[] { type });
return _db
.GetType()
.GetMethods()
.Where( m => m.ReturnType == targetType)
.Single()
.Invoke(_db, null) as IEnumerable;
}
}
public static void Main()
{
var helperClass = new HelperClass(new DatabaseContext());
foreach (var u in helperClass.GetDataSource<User>())
{
Console.WriteLine(u);
}
foreach (var t in helperClass.GetDataSource(typeof(Transaction)))
{
Console.WriteLine(t);
}
}
}
Output:
User Bob
User Alice
Transaction 12.34
Transaction 56.78
Full code on DotNetFiddle
This approach was not plausible and I ended up storing the datasource of the GridView in a SessionState variable. Saved having to requery for the DataSource each postback (could get tedious if I had to keep track of order bys when requerying. instead the sessionstate variable keeps the sort order)

Getting class property by name

I'm overriding the ValidateEntity method to check for unique validation and I've hit a stumbling block.
protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
{
var result = new DbEntityValidationResult(entityEntry, new List<DbValidationError>());
if (entityEntry.Entity is ReferenceType && entityEntry.State == EntityState.Added)
{
var entity = entityEntry.Entity as ReferenceType;
var pluralService = PluralizationService.CreateService(CultureInfo.GetCultureInfo("en-gb"));
var pluralEntity = pluralService.Pluralize(entity.GetType().Name);
// I would like Courses to be replaced with the property name of pluralEntity
if (Courses.Where(x => x.Title == entity.Title).Count() > 0)
{
result.ValidationErrors.Add(new DbValidationError(nameof(entity.Title), nameof(entity.Title) + " must be unique."));
}
}
if (result.ValidationErrors.Count > 0)
{
return result;
}
else
{
return base.ValidateEntity(entityEntry, items);
}
}
In my SchoolContext class I have the property DbSet<Course> Courses which is a ReferenceType (a custom abstract class type).
The value of pluralEntity is Courses, but I want to put in the if-statement something similar to:
if (Property(pluralEntity).Where(x => x.Title == entity.Title).Count() > 0)
{
// validate
}
Is there a way to do this?
Update
I've got this:
var prop = (DbSet<ReferenceType>) GetType().GetProperty(pluralEntity).GetValue(this, null);
if (prop.Where(x => x.Title == entity.Title).Count() > 0)
{
result.ValidationErrors.Add(new DbValidationError(nameof(entity.Title), nameof(entity.Title) + " must be unique."));
}
But because ReferenceType is an abstract class it cannot cast it at runtime.
I'd like to do something like this
var prop = (DbSet<typeof(entityEntry.Entity.GetType().Name)>)
But of course that's a variable and can't be passed in as a generic type
The only thing I can think of at the moment is writing a custom validation method, using the repository pattern.
First, create an interface which all your entities will implement
public interface IEntity
{
public string Title {get; set; }
}
Then create the repository:
public class Repository<TEntity> where TEntity: class, IEntity
{
private YourContext context = new YourContext();
private DbSet<TEntity> AppDbSet;
public Repository()
{
AppDbSet = context.Set<TEntity>();
}
//a couple of method to retrieve data...
public List<TEntity> GetAll()
{
return AppDbSet.ToList();
}
public IEnumerable<TEntity> Find(Func<TEntity, bool> predicate)
{
return AppDbSet.Where<TEntity>(predicate);
}
public TEntity Single(Func<TEntity, bool> predicate)
{
return AppDbSet.FirstOrDefault(predicate);
}
//Lastly, implement a validation method
public bool IsValid(TEntity entity)
{
if (AppDbSet.SingleOrDefault(x => x.Title == entity.Title) != null)
return false;
else
return true;
}
}
Use the repository as follow:
Repository<Course> courseRepository = new Repository<Course>();
Course course = new Course();
course.Title = "Boring course";
Console.WriteLine(courseRepository.IsValid(course));
Hope it helps.

Many-To-Many Generic Update Method with Entity Framework 6

I have a generic Update method for Entity Framework in an abstract DatabaseOperations<T,U> class:
public virtual void Update(T updatedObject, int key)
{
if (updatedObject == null)
{
return;
}
using (var databaseContext = new U())
{
databaseContext.Database.Log = Console.Write;
T foundEntity = databaseContext.Set<T>().Find(key);
databaseContext.Entry(foundEntity).CurrentValues.SetValues(updatedObject);
databaseContext.SaveChanges();
}
}
However, this does not handle many-to-many relationships.
This many-to-many update problem can be overcome by overriding the Update method in TrussSetDatabaseOperations : DatabaseOperations<TrussSet, TrussManagementDatabaseContext> to read as follows:
public override void Update(TrussSet updatedTrussSet, int key)
{
if (updatedTrussSet == null)
{
return;
}
using (var databaseContext = new TrussManagementDatabaseContext())
{
databaseContext.Database.Log = Console.Write;
TrussSet foundTrussSet = databaseContext.TrussSets.Find(key);
databaseContext.Entry(foundTrussSet).CurrentValues.SetValues(updatedTrussSet)
// Update the many-to-many relationship of TrussSets to Seals
databaseContext.Entry(foundTrussSet).Collection(trussSet => trussSet.Seals).Load();
databaseContext.Entry(foundTrussSet).Collection(trussSet => trussSet.Seals).CurrentValue = updatedTrussSet.Seals;
databaseContext.SaveChanges();
}
}
However, this overriding would proliferate through all the classes that inherit from DatabaseOperations and have a TrussSet object. Can I somehow inject the added two lines into the generic update method, so that the update method is given the collection properties, loads them, and applies the respective updated collection to that entity? Thanks in advance.
Looking at your code, the following comes to mind:
public virtual void Update(T updatedObject, int key, params string[] navigationProperties) {
if (updatedObject == null) {
return;
}
using (var databaseContext = new U()) {
databaseContext.Database.Log = Console.Write;
T foundEntity = databaseContext.Set<T>().Find(key);
var entry = databaseContext.Entry(foundEntity);
entry.CurrentValues.SetValues(updatedObject);
foreach (var prop in navigationProperties) {
var collection = entry.Collection(prop);
collection.Load();
collection.CurrentValue = typeof(T).GetProperty(prop).GetValue(updatedObject);
}
databaseContext.SaveChanges();
}
}
You can also use Expressions instead of strings (and then extract property names from those expressions) if you want more type-safety.
Update: here is what I mean by "use Expressions" in this case:
public virtual void Update(T updatedObject, int key, params Expression<Func<T, IEnumerable>>[] navigationProperties) {
if (updatedObject == null) {
return;
}
using (var databaseContext = new U()) {
databaseContext.Database.Log = Console.Write;
T foundEntity = databaseContext.Set<T>().Find(key);
var entry = databaseContext.Entry(foundEntity);
entry.CurrentValues.SetValues(updatedObject);
foreach (var prop in navigationProperties) {
string memberName;
var member = prop.Body as MemberExpression;
if (member != null)
memberName = member.Member.Name;
else throw new Exception("One of the navigationProperties is not a member access expression");
var collection = entry.Collection(memberName);
collection.Load();
collection.CurrentValue = typeof (T).GetProperty(memberName).GetValue(updatedObject);
}
databaseContext.SaveChanges();
}
}

c# - Castle - No component for supporting the service - Fluent registration and resolution of Generic with generics parameters

If i use one-by-one component registration everything resolves ok.. my problem is fluent registration, any thoughts?
Example
public class MyFilter:Filter {}
public class MyEntity:Entity {}
public class ReadCommandHandler<TEntity,TFilter> : ICommandHandler<IReadCommand<TFilter>, IEnumerable<TEntity>> where TEntity : Entity where TFilter : Filter
Installer
container.Register(Types.FromThisAssembly().BasedOn(typeof(ICommandHandler<,>)).WithService.AllInterfaces());
this results in (debugger view)
ReadCommandHandler<·TEntity·, ·TFilter·> / ICommandHandler< IReadCommand<·TFilter·>, IEnumerable<·TEntity·>>
so it seems is ok .. but then if i tried this
var biz = container.Resolve(typeof(ICommandHandler<IReadCommand<MyFilter>,IEnumerable<MyEntity>>))
or this
var biz = container.Resolve(typeof(ICommandHandler<IReadCommand<Filter>,IEnumerable<Entity>>))
the result is "No component for supporting the service"
whats the matter with this?
Okay .. as one possible approach i "resolved" this with IGenericImplementationMatchingStrategy
Setup and resolve:
var container = new WindsorContainer();
container.Register(
Types.FromAssemblyContaining(typeof(ReadCommandHandler<,>)).BasedOn(typeof(ICommandHandler<,>))
.If(p => !p.IsInterface)
.WithServiceBase()
.Configure(
c => c.ExtendedProperties(
Property.ForKey(Castle.Core.Internal.Constants.GenericImplementationMatchingStrategy)
.Eq(new GenericImplementationMatchingStrategy()))));
var biz = container.Resolve(typeof(ICommandHandler<IReadCommand<MyFilter>, IEnumerable<MyEntity>>));
GenericStrategyImplementation
public class GenericImplementationMatchingStrategy : IGenericImplementationMatchingStrategy
{
public static ConcurrentDictionary<string, Type[]> dicStrategyCommandHandler = new ConcurrentDictionary<string, Type[]>();
public Type[] GetGenericArguments(ComponentModel model, CreationContext context)
{
return dicStrategyCommandHandler.GetOrAdd(context.RequestedType.FullName, (key) =>
{
if (context.RequestedType.GetGenericTypeDefinition() == typeof(ICommandHandler<,>))
{
var service = model.Implementation.GetInterfaces().Where(p => { return p.Name == context.RequestedType.Name; }).FirstOrDefault(); // model.Implementation.GetInterfaces()[0];
if (service != null)
{
List<Type> types = new List<Type>();
foreach (var item in model.Implementation.GetGenericArguments())
{
var name = item.Name;
var type = serviceGetType(name, service, context.RequestedType);
types.Add(type);
}
return types.ToArray();
}
}
return null;
}
);
}
private Type serviceGetType(string name, Type service, Type requestedType)
{
var args = service.GetGenericArguments().ToArray();
var argsRequested = requestedType.GetGenericArguments().ToArray();
for (int i=0;i<args.Count();i++ )
{
Type itemDecla = args[i];
Type itemRequested = argsRequested[i];
if (itemDecla.Name == name)
return itemRequested;
else
{
var recur = serviceGetType(name, itemDecla, itemRequested);
if (recur != null) return recur;
}
}
return null;
}
}
What do you think .. something better?
My only nice-to-know question is, why if my component lifestyle is singleton, the resolve method calls GenericImplementationMatchingStrategy each time i call Resolve(..).

Categories