I have the following method:
protected override void OnModelCreating(ModelBuilder builder) {
builder.Map<Country>();
}
And I created the following extension:
public static class CountryMapper {
public static void Map<T>(this ModelBuilder builder) where T : Country {
builder.Entity<T>().HasKey(x => x.Code);
}
}
This works but I would like to have a generic base class:
public class CountryMapper : EntityMapper<Country> {
// Here override the map extension ??
}
Basically I would like to apply Map as I am but assuring all Mappers are implemented the same way.
EntityMapper is a class made by you?
and Country can be modified?
I'd add an interface like IEntity that expose a GetKey method like
public interface IEntity {
object GetKey();
}
then in country (and every class you need to map), implement that interface, e.g your country could looks like
public class Country : IEntity{
public string Code { get; set; }
...
public object GetKey(){
return this.Code;
}
...
}
then your Map Extension could be generic and based on this interface, like
public static void Map<T>(this ModelBuilder builder) where T : IEntity {
builder.Entity<T>().HasKey(x => x.GetKey());
}
note that i wrote it without having a chance to test, but this should point you to the right direction, there is even a little chance this is already working :)
P.S.
if you don't like to have that GetKey method to be easily accessed by anyone (or seen when using visual studio) you can implement it as an explicit interface
should be
public class Country : IEntity{
public string Code { get; set; }
...
object IEntity.GetKey(){
return this.Code;
}
...
}
and then extension, semething like
public static void Map<T>(this ModelBuilder builder) where T : IEntity {
builder.Entity<T>().HasKey(x => ((IEntity)x).GetKey());
}
Related
Consider the following abstract class :
public abstract class BuildingBase
{
public abstract BuildingType Type { get; }
}
this class is inherited by two classes :
public class Appartment : BuildingBase
{
public override BuildingType Type => BuildingType.Appartment;
}
public class House: BuildingBase
{
public override BuildingType Type => BuildingType.House;
}
I have a factory that should 'build' based on the type passed :
public class Builder {
public BuildingBase Build(BuildingType type) {
// how to get this implemented without if / else .. case when ... etc
}
}
I'd use generics in this case, like this:
public class Builder
{
public TBuildingBase Build<TBuildingType>()
where TBuildingBase : BuildingBase, new()
{
var result = new TBuildingBase();
...
}
}
But I'm not sure if you require the Enum as an input. I'm afraid that if you do want to stick with it, your choices are either an if-else construct, a constructor map like #Selvin mentioned, or using reflection (ugh).
I'm trying to create a generic configuration class for my entities but i'm stuck.
I have an abstract class called EntityBase:
public abstract class EntityBase
{
public int Id { get; set; }
public int TenantId { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
}
And many other classes that inherit from EntityBase, in which i have to configure the DateTime properties in each one with the same code. This way:
void EntityTypeConfiguration<MyEntity>.Configure(EntityTypeBuilder<MyEntity> builder)
{
builder.HasIndex(e => e.TenantId);
builder.Property(e => e.CreatedOn)
.ValueGeneratedOnAdd()
.HasDefaultValueSql("GETDATE()");
// Other specific configurations here
}
I would like to be able to call somthing like: builder.ConfigureBase() and avoid the code duplication. Any ideas?
There are several way you can accomplish the goal. For instance, since you seem to be using IEntityTypeConfiguration<TEntity> classes, you could create a base generic configuration class with virtual void Configure method and let your concrete configuration classes inherit from it, override the Configure method and call base.Configure before doing their specific adjustments.
But let say you want to be able to exactly call builder.ConfigureBase(). To allow that syntax, you can simply move the common code to a custom generic extension method like this:
public static class EntityBaseConfiguration
{
public static void ConfigureBase<TEntity>(this EntityTypeBuilder<TEntity> builder)
where TEntity : EntityBase
{
builder.HasIndex(e => e.TenantId);
builder.Property(e => e.CreatedOn)
.ValueGeneratedOnAdd()
.HasDefaultValueSql("GETDATE()");
}
}
with sample usage:
void IEntityTypeConfiguration<MyEntity>.Configure(EntityTypeBuilder<MyEntity> builder)
{
builder.ConfigureBase();
// Other specific configurations here
}
I was curious if it was possible to create like a parent abstract class that I can define a specific set of methods in but have the children classes include different entity types? Code Example:
public abstract class BaseService
{
public abstract void Add();
public abstract void Delete();
public abstract void Update();
public abstract void Get();
}
Maybe be able to do something like public abstract List<'random type'> GetAll();
But here i would want to override each method with specific parameters that are specific to each of its children:
public class CategoryService : BaseService
{
public override void Add(){ }
public override void Delete(){ }
public override void Update(){ }
public override void Get(){ }
}
However, in my child class, I would want my Get() method to return a specific List<"of Type"> (in this case Category). Furthermore, I might want to do public override Add(int CategoryID) instead of the inherited Add from BaseService.
Is this possible? Thoughts? Am I just crazy? Or am I trying to make this more complicated than it needs to be? I have about 10 different service types that I want to make sure get those generic methods from BaseService.
Thanks in advance!
You could do this if I understand you correctly:
public abstract class BaseService<T>
{
public abstract T Get();
}
Then:
public class CategoryService : BaseService<Category>
{
public override Category Get(){ ... }
}
You can't override methods and have a different signature in the override, but you could use a dictionary/hashtable or something more fancy to pass parameters into the Add method. Passing parameters in using a generic container would mean you are starting to use the query pattern where the parameters in the container determine the query (just for info :-)).
Try using generic type
public abstract List<T> GetAll<T>();
And return appropriate type in your child class
Update
#pw94 answer is also a good way to achieve this, but the only problem is you cannot have multiple type for different methods, only one type will work once you inherit the class.
You can create abstract generic class:
public abstract class BaseService<T>
{
public abstract void Add();
public abstract List<T> Get();
}
And implement:
public class CategoryService : BaseService<int>
{
public override void Add(){ ... }
public override List<int> Get(){ ... }
}
Given the following two classes
public class LocalFoo {
}
public class RemoteFoo {
}
Both of these classes SHOULD have similar properties :
public string strBar{ get; set; }
public int intBar{ get; set; }
The difference being how those properties are set and read - in the former case the properties are handled locally - by the program. In the latter, the properties are read and written directly from and two a DataTable read from a Database.
I know that Inheritance is going to have to happen here but that's where I'm getting stuck.
For example, if I declare a method TakesFoo :
public void takesFoo( Foo bar ){
/*Magic Happens Here*/
}
I want that to be able to call that method with an object of either type LocalFoo or RemoteFoo.
I know I could write an abstract class Foo :
public abstract class Foo{
}
and have both LocalFoo and RemoteFoo inherit from it but there's a caveat - I have another abstract class which I need RemoteFoo to inherit that is used making it easier to read/write to/from DataTables -
public abstract class DRHelper : IEquatable<DRHelper>, IDisposable {
}
My initial instinct is to make Foo an interface but I don't know if that will work and I was hoping someone could give me some direction on how I should handle this problem.
Create an IFoo interface that has:
string strBar{ get; set; }
int intBar{ get; set; }
class LocalFoo and class RemoteFoo would both need to implement the IFoo interface.
then change your method as:
public void takesFoo( IFoo bar ){
/*Magic Happens Here*/
}
I think, you should use Visitor Pattern
It allows you to avoid if(bar is LocalFoo) code.
public abstract class Foo
{
public abstract void Accept(IVisitor visitor);
}
public class LocalFoo : Foo
{
public override void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
}
public class RemoteFoo : Foo
{
public override void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
}
public interface IVisitor
{
void Visit(LocalFoo foo);
void Visit(RemoteFoo foo);
}
public class Visitor : IVisitor
{
public void Visit(RemoteFoo foo)
{
/*Magic Happens Here*/
}
public void Visit(LocalFoo foo)
{
/*Magic Happens Here*/
}
}
Here is the code, last line is the highlight of what I am doing:
public interface IHasContext<TContext> {
TContext Context {get; set;}
}
public static class Extensions {
public static void ProcessContext<THasContext, TContext>(this THasContext t)
where THasContext : IHasContext<TContext>
where TContext : class {
//...
}
}
public class SomeClassContext {/*...*/}
public class SomeClass : IHasContext<SomeClassContext> {
public SomeClassContext Context {get; set;}
//...
}
//now in a function I can do:
objSomeClass.ProcessContext<SomeClass, SomeClassContext>();
You see, because SomeClass already knows it contains <SomeClassContext>, so I want to do:
objSomeClass.ProcessContext();
without the <SomeClass, SomeClassContext> chunk. Is it possible? How should I alter my code to achieve it? Thank you :)
I don't see why you need two generic parameters. Just use one:
public static class Extensions {
public static void ProcessContext<TContext>(this IHasContext<TContext> t)
where TContext : class {
//...
}
}
Then inference should work just fine:
var obj = new SomeClass();
obj.ProcessContext();
There is one slight semantic difference between the two. If the type SomeClass was a struct then your version would not box the argument t, while this version will causing boxing.