I am trying to use the DataConnection class of linq2db in an abstract base class like so:
public abstract class BaseDbDao<T> : DataConnection where T : IDatabase
{
public string DBName => DBContext.Database;
public T DBContext { get; }
public DataConnection GetDataConnection()
{
return (this);
}
internal BaseDbDao(RelativityHelper helper, int workspaceId)
: base(GetDataProvider(), helper.GetDBContextNew(workspaceId).GetConnection())
{
DBContext = (T)helper.GetDBContextNew(workspaceId);
}
public static IDataProvider GetDataProvider()
{
LinqToDB.Common.Configuration.AvoidSpecificDataProviderAPI = true;
return new SqlServerDataProvider("", SqlServerVersion.v2017);
}
}
I am then calling it up from another class like so:
public class EdMeDBDao : BaseDbDao<MSSQLDBContext>
{
public ITable<EdMeTableRow> EdMeDatabase => GetTable<EdMeTableRow>();
public EdMeDBDao(RelativityHelper helper)
: base(helper, "123456")
{
}
public List<RelativityWorkspace> GetActiveProjects()
{
using (var db = GetDataConnection())
{
var a = GetTable<EdMeTableRow>().CaseName
};
}
}
However, I can't seem to call var a = GetTable<EdMeTableRow>().CaseName as ITable<EdMeTableRow> does not contain a definition for 'CaseName'
EdMeTableRow is defined as:
[Table(Name = "NuixWorkflowCases", Schema = "dbo")]
public class EdMeTableRow
{
public string CaseName { get; set; }
}
How can I access EdMeTableRow class from the EdMeDBDao class?
Related
I have the following class that implements dependency injection for ISecurityRepository:
public class SecurityService : BaseService
{
ISecurityRepository _securityRepo = null;
public SecurityService(ISecurityRepository securityRepo)
{
_securityRepo = securityRepo;
}
}
Then I have the SecurityRepository class as follows:
public class SecurityRepository : BaseRepository, ISecurityRepository
{
public bool ValidateLogin(string userName, string password)
{
return true;
}
}
Then BaseRepository class:
public abstract class BaseRepository
{
private string _customString = null;
public string CustomString{
get {
return _customString ;
}
set
{
value = _customString ;
}
}
}
What I need is to set CustomString on BaseRepository class value from SecurityService class. Something maybe like this:
public class SecurityService : BaseService
{
ISecurityRepository _securityRepo = null;
public SecurityService(ISecurityRepository securityRepo)
{
_securityRepo = securityRepo;
// something like this or better way
_securityRepo.CustomString = "ABCD";
}
}
The idea is that within SecurityRepository class I can access CustomString value.
Is it possible that each class object has its own static data store?
I mean, just to perform actions like:
class Program
{
static void Main(string[] args)
{
var car1 = new Car();
car1.Save(); ////saves in its own storage
var own1 = new Owner();
own1.Save(); //saves in its own storage as well
}
}
In code I tried, I get such error
'System.InvalidCastException`
at this place
var repo = (Repository<IEntity>) CurrentRepository;
Whats wrong and how could I make it?
Whole code is here:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
//var car1 = new Car();
//car1.Save(); ////saves in its own storage
//var own1 = new Owner();
//own1.Save(); //saves in its own storage as well var car1 = new Car();
}
}
public interface IEntity
{
long Id { get; }
}
public class Owner : Entity
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Car Car { get; set; }
public Owner(string firstName, string lastName, Car car) : base(new Owner())
{
FirstName = firstName;
LastName = lastName;
Car = car;
}
public Owner() : base()
{
}
}
public class Car : Entity
{
public string Name { get; set; }
public int Year { get; set; }
public Car() : base()
{
}
public Car(string name, int year)
{
Name = name;
Year = year;
}
}
public abstract class Entity : IEntity
{
public long Id { get; }
public static object CurrentRepository { get; set; }
public Entity(Entity ent)
{
Type entityType = ent.GetType();
var instance = Activator.CreateInstance(typeof(Repository<>).MakeGenericType(entityType));
CurrentRepository = instance;
}
public Entity()
{
}
public void Save()
{
var repo = (Repository<IEntity>)CurrentRepository;
repo.Save(this);
}
public void Delete()
{
var repo = (Repository<IEntity>)CurrentRepository;
repo.Delete(this);
}
}
public interface IRepository<T> where T : IEntity
{
void Save(T entity);
void Delete(T entity);
T Find(long id);
}
public class Repository<T> : IRepository<T> where T : class, IEntity
{
protected BaseStorage<T> CustomDataStorage;
public Repository()
{
CustomDataStorage = new BaseStorage<T>();
}
public void Save(T entity)
{
CustomDataStorage.Add(entity);
}
public void Delete(T entity)
{
CustomDataStorage.Remove(entity);
}
public T Find(long id)
{
throw new NotImplementedException();
}
}
public class BaseStorage<T> : IStorage<T>
{
List<T> data = new List<T>();
public void Add(T entity)
{
data.Add(entity);
}
public void Remove(T entity)
{
throw new NotImplementedException();
}
}
public interface IStorage<T>
{
void Add(T entity);
void Remove(T entity);
}
}
In code I tried, I get such error
'System.InvalidCastException`
at this place var repo = (Repository) CurrentRepository;
Whats wrong and how could I make it?
That's because you can't directly cast the CurrentRepository, a type of (Repository<Car> or Repository<Owner>) into a Repository<IEntity>.
See here for more information on this...
To achieve what you wanted here, you could try it this way:
Make the Entity class generic (Entity<T>) and constraint the generic type as IEntity
Make the CurrentRepository a type of Repository<Entity<T>>
Move the static initialization of CurrentRepository from instance constructor to the static constructor.
Make the Owner and Car object subclass of Entity<T> with T refers to its own type making it a self referencing generics
Code:
public class Owner : Entity<Owner>
{
...
}
public class Car : Entity<Car>
{
...
}
public abstract class Entity<T> : IEntity
where T: IEntity
{
public long Id { get; }
public static Repository<Entity<T>> CurrentRepository { get; set; }
static Entity()
{
CurrentRepository = new Repository<Entity<T>>();
}
public Entity()
{
}
public void Save()
{
CurrentRepository.Save(this);
}
public void Delete()
{
CurrentRepository.Delete(this);
}
}
One option to consider would be to change Entity as below.
The ConcurrentDictionary is to ensure that you get one repository per type.
public abstract class Entity : IEntity
{
public long Id { get; }
public static ConcurrentDictionary<Type, dynamic> CurrentRepository = new ConcurrentDictionary<Type, dynamic>();
public Entity(Entity ent)
{
GetRepository(ent);
}
private static dynamic GetRepository(Entity ent)
{
Type entityType = ent.GetType();
return CurrentRepository.GetOrAdd(entityType, type =>
{
var instance = Activator.CreateInstance(typeof(Repository<>).MakeGenericType(entityType));
return instance;
});
}
public Entity()
{
}
public void Save()
{
var repo = GetRepository(this);
repo.Save((dynamic)this);
}
public void Delete()
{
var repo = GetRepository(this);
repo.Delete((dynamic)this);
}
}
I have below object model with simple inheritance:
public class RuntimeApiManagerBase
{
}
public class CatalogRuntimeApiManagerBase : RuntimeApiManagerBase
{
public void Method1()
{
}
}
public class DocumentRuntimeApiManagerBase : RuntimeApiManagerBase
{
public void Method2()
{
}
public void Method3()
{
}
}
public class BaseObject
{
public BaseObject(RuntimeApiManagerBase runtimeApiMgr)
{
RuntimeApiMgr = runtimeApiMgr;
}
public RuntimeApiManagerBase RuntimeApiMgr { get; set; }
}
public class Catalog : BaseObject
{
public Catalog() : base(new CatalogRuntimeApiManagerBase())
{
}
}
public class Document : BaseObject
{
public Document() : base(new DocumentRuntimeApiManagerBase())
{
}
}
Now, I want to access RuntimeApiMgr Property's Methods based on exactly derived type. However, it displays nothing which is logical:
Catalog c1 = new Catalog();
// c1.RuntimeApiMgr. => No Method1
Document d1 = new Document();
// d1.RuntimeApiMgr. => No Method2 and Method3
Is that possible using different structure like Generics or something else?
Thanks for your time.
Use generics:
public class BaseObject<T>
where T : RuntimeApiManagerBase
{
public BaseObject(T runtimeApiMgr)
{
RuntimeApiMgr = runtimeApiMgr;
}
public T RuntimeApiMgr { get; set; }
}
public class Catalog : BaseObject<CatalogRuntimeApiManagerBase>
{
public Catalog() : base(new CatalogRuntimeApiManagerBase())
{
}
}
public class Document : BaseObject<DocumentRuntimeApiManagerBase>
{
public Document() : base(new DocumentRuntimeApiManagerBase())
{
}
}
In that case your c1.RuntimeApiMgr will be of the type CatalogRuntimeApiManagerBase and will have Method1
You can use RuntimeApiManagerBase as generic and have a type constraint where T must be a subclass of RuntimeApiManagerBase
public class BaseObject<T> where T : RuntimeApiManagerBase
{
public BaseObject(T runtimeApiMgr)
{
RuntimeApiMgr = runtimeApiMgr;
}
public T RuntimeApiMgr { get; set; }
}
public class Catalog : BaseObject<CatalogRuntimeApiManagerBase>
{
public Catalog() : base(new CatalogRuntimeApiManagerBase())
{
}
}
public class Document : BaseObject<DocumentRuntimeApiManagerBase>
{
public Document() : base(new DocumentRuntimeApiManagerBase())
{
}
}
Catalog c1 = new Catalog();
c1.RuntimeApiMgr.Method1();
Document d1 = new Document();
d1.RuntimeApiMgr.Method2();
Alternative to solution with generics is an old fashioned approach with casting.
Maybe something like this:
Catalog c1 = new Catalog();
(c1.RuntimeApiMgr as CatalogRuntimeApiManagerBase).Method1();
Document d1 = new Document();
(d1.RuntimeApiMgr as DocumentRuntimeApiManagerBase).Method2();
Or create new properties with the same name in Caltalog and Document classes:
public class Catalog : BaseObject
{
public Catalog() : base(new CatalogRuntimeApiManagerBase())
{
}
public new CatalogRuntimeApiManagerBase RuntimeApiMgr { get; set; }
}
I have an interface like this
public interface IPerson { }
And implementations
public class Fireman : IPerson
{
public string Name { get; set; }
public bool WithAssignedTruck { get; set; }
...
}
public class Pilot : IPerson
{
public string Name { get; set; }
public int Age { get; set; }
...
}
And pass them to a constructor
public class Registration : IRegistration
{
private readonly Fireman _fireman;
private readonly Pilot _pilot;
public Registration(Pilot pilot, Fireman fireman)
{
this._fireman = fireman;
this._pilot = pilot;
}
}
And here's what the initialization method looks like.
public T PopulateProfile<T>() where T : IPerson, new()
{
var personProfile = Activator.CreateInstance<T>();
...
return personProfile;
}
Please take note that this code is just an example.
I have a method that will set the value of each property of these classes which are from database. What I need to do is that, when I ask Ninject for any class that implements IPerson interface, Ninject should execute the method first, thus, Ninject will return an initialized class. Hope you could give me a hand. Thank you.
You can use Ninject.Extensions.Conventions in combination with an IBindingGenerator which generates a ToMethod binding:
BindingGenerator
internal class PersonBindingGenerator : IBindingGenerator
{
private static readonly MethodInfo PopulateOpenGenericMethodInfo =
typeof(IProfileService).GetMethod("PopulateProfile");
public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(
Type type,
IBindingRoot bindingRoot)
{
yield return bindingRoot
.Bind(type)
.ToMethod(x => CreatePerson(x.Kernel.Get<IProfileService>(), type));
}
private static object CreatePerson(
IProfileService profileService,
Type type)
{
var closedGeneric = PopulateOpenGenericMethodInfo.MakeGenericMethod(type);
return closedGeneric.Invoke(profileService, new object[0]);
}
}
Bindings
kernel.Bind<IProfileService>().To<ProfileService>();
kernel.Bind(s => s
.FromThisAssembly()
.IncludingNonePublicTypes()
.SelectAllClasses()
.InheritedFrom<IPerson>()
.BindWith<PersonBindingGenerator>());
Test
Complete Test code for reference.
using FluentAssertions;
using Ninject;
using Ninject.Extensions.Conventions;
using Ninject.Extensions.Conventions.BindingGenerators;
using Ninject.Syntax;
using System;
using System.Collections.Generic;
using System.Reflection;
using Xunit;
namespace NinjectTest.SO36424126
{
public interface IPerson
{
string SomeValue { get; set; }
}
class BarPerson : IPerson
{
public string SomeValue { get; set; }
}
class FooPerson : IPerson
{
public string SomeValue { get; set; }
}
public interface IProfileService
{
T PopulateProfile<T>()
where T : IPerson, new();
}
internal class ProfileService : IProfileService
{
public T PopulateProfile<T>()
where T : IPerson, new()
{
var personProfile = Activator.CreateInstance<T>();
personProfile.SomeValue = "initialized";
return personProfile;
}
}
internal class PersonBindingGenerator : IBindingGenerator
{
private static readonly MethodInfo PopulateOpenGenericMethodInfo = typeof(IProfileService).GetMethod("PopulateProfile");
public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
{
yield return bindingRoot
.Bind(type)
.ToMethod(x => CreatePerson(x.Kernel.Get<IProfileService>(), type));
}
private static object CreatePerson(IProfileService profileService, Type type)
{
var closedGeneric = PopulateOpenGenericMethodInfo.MakeGenericMethod(type);
return closedGeneric.Invoke(profileService, new object[0]);
}
}
public class Test
{
[Fact]
public void Foo()
{
var kernel = new StandardKernel();
kernel.Bind<IProfileService>().To<ProfileService>();
kernel.Bind(s => s
.FromThisAssembly()
.IncludingNonePublicTypes()
.SelectAllClasses()
.InheritedFrom<IPerson>()
.BindWith<PersonBindingGenerator>());
kernel.Get<BarPerson>().SomeValue.Should().Be("initialized");
}
}
}
When having the following scenario I am unhappy with the consuming code that is littered with the line
var queryResult = _queryDispatcher.Dispatch<CustomerByIdQuery, CustomerByIdQueryResult>(customerByIdQuery).Customer;
I would prefer to have the code work this way for the consumer:
var queryResult = _queryDispatcher.Dispatch(customerByIdQuery).Customer;
Is there a way to accomplish this using generics?
Here is the code
interface IQuery{}
interface IQueryResult{}
interface IQueryHandler<TQuery, TQueryResult> : where TQueryResult:IQueryResult where TQuery:IQuery
{
TQueryResult Execute(TQuery query);
}
interface IQueryDispatcher
{
TQueryResult Dispatch<TQuery, TQueryResult>(TQuery query) where TQuery:IQuery where TQueryResult:IQueryResult
}
class GenericQueryDispatcher : IQueryDispatcher
{
public TQueryResult Dispatch<TQuery, TQueryResult>(TQuery parms)
{
var queryHandler = queryRegistry.FindQueryHandlerFor(TQuery);
queryHandler.Execute
}
}
class CustomerByIdQuery : IQuery
{
public int Id { get; set; }
}
class CustomerByIdQueryResult : IQueryResult
{
public Customer {get; set;}
}
class CustomerByIdQueryHandler : IQueryHandler
{
public CustomerByIdQueryResult Execute(TQuery query)
{
var customer = _customerRepo.GetById(query.Id);
return new CustomerByIdQueryResult(){Customer = customer};
}
}
public class SomeClassThatControlsWorkFlow
{
IQueryDispatcher _queryDispatcher;
public SomeClassThatControlsWorkFlow(IQueryDispatcher queryDispatcher)
{
_queryDispatcher = queryDispatcher;
}
public void Run()
{
var customerByIdQuery = new CustomerByIdQuery(){Id=1};
//want to change this line
var customer = _queryDispatcher.Dispatch<CustomerByIdQuery, CustomerByIdQueryResult>(customerByIdQuery).Customer;
}
}
Here is what I would like to have :
public class ClassWithRunMethodIWouldLikeToHave
{
IQueryDispatcher _queryDispatcher;
public SomeClassThatControlsWorkFlow(IQueryDispatcher queryDispatcher)
{
_queryDispatcher = queryDispatcher;
}
public void Run()
{
var customerByIdQuery = new CustomerByIdQuery(){Id=1};
//want to change this line
var customer = _queryDispatcher.Dispatch(customerByIdQuery).Customer;
}
}
Yes, it's possible, but you have to make the Dispatch method's parameter generic (that way, the compiler can infer the type parameters from the method parameter). To do this, it looks like you'll first need a generic version of the IQuery and IQueryResult interfaces:
interface IQuery<TQuery, TQueryResult> : IQuery {}
interface IQueryResult<T> : IQueryResult
{
T Result { get; }
}
Next, make CustomerByIdQuery and CustomerByIdQueryResult implement the respective generic interfaces:
class CustomerByIdQuery : IQuery, IQuery<int, Customer>
{
public int Id { get; set; }
}
class CustomerByIdQueryResult : IQueryResult, IQueryResult<Customer>
{
public Customer Result {get; set;}
}
Now you can add an overload for Dispatch that accepts the generic parameter:
interface IQueryDispatcher
{
IQueryResult<TQueryResult> Dispatch<TQuery, TQueryResult>(IQuery<TQuery, TQueryResult> parms);
}
class GenericQueryDispatcher : IQueryDispatcher
{
public TQueryResult Dispatch<TQuery, TQueryResult>(IQuery<TQuery, TQueryResult> parms)
{
// TODO implement
}
}
The above will allow you to write:
var customerByIdQuery = new CustomerByIdQuery{Id=1};
var customer = _queryDispatcher.Dispatch(customerByIdQuery).Result;
I can't get rid of the cast, but this is working pretty close to what I want.
public interface IQueryDispatcher
{
TQueryResult Dispatch<TParameter, TQueryResult>(IQuery<TQueryResult> query)
where TParameter : IQuery<TQueryResult>
where TQueryResult : IQueryResult;
}
public interface IQueryHandler<in TQuery, out TQueryResult>
where TQuery : IQuery<TQueryResult>
where TQueryResult : IQueryResult
{
TQueryResult Retrieve(TQuery query);
}
public interface IQueryResult { }
public interface IQuery { }
public interface IQuery<TQueryResult> : IQuery { }
public class QueryDispatcher : IQueryDispatcher
{
readonly IQueryHandlerRegistry _queryRegistry;
public QueryDispatcher(IQueryHandlerRegistry queryRegistry)
{
_queryRegistry = queryRegistry;
}
public TQueryResult Dispatch<TQuery, TQueryResult>(IQuery<TQueryResult> query)
where TQuery : IQuery<TQueryResult>
where TQueryResult : IQueryResult
{
var handler = _queryRegistry.FindQueryHandlerFor<TQuery, TQueryResult>(query);
//CANT GET RID OF CAST
return handler.Retrieve((TQuery)query);
}
}
public interface IQueryHandlerRegistry
{
IQueryHandler<TQuery, TQueryResult> FindQueryHandlerFor<TQuery, TQueryResult>(IQuery<TQueryResult> query)
where TQuery : IQuery<TQueryResult>
where TQueryResult : IQueryResult;
}
public class GetCustByIdAndLocQuery : IQuery<CustByIdAndLocQueryResult>
{
public string CustName { get; set; }
public int LocationId { get; set; }
public GetCustByIdAndLocQuery(string name, int locationId)
{
CustName = name;
LocationId = locationId;
}
}
public class CustByIdAndLocQueryResult : IQueryResult
{
public Customer Customer { get; set; }
}
public class GetCustByIdAndLocQueryHandler : IQueryHandler<GetCustByIdAndLocQuery, CustByIdAndLocQueryResult>
{
readonly ICustomerGateway _customerGateway;
public GetCustByIdAndLocQueryHandler(ICustomerGateway customerGateway)
{
_customerGateway = customerGateway;
}
public CustByIdAndLocQueryResult Retrieve(GetCustByIdAndLocQuery query)
{
var customer = _customerGateway.GetAll()
.SingleOrDefault(x => x.LocationId == query.LocationId && x.CustomerName == query.CustName);
return new CustByIdAndLocQueryResult() { Customer = customer };
}
}
public interface ICustomerGateway
{
IEnumerable<Customer> GetAll();
}
public class Customer
{
public string CustomerName { get; set; }
public int LocationId { get; set; }
public bool HasInsurance { get; set; }
}