i would like to implement a dynamic way of creating entities for EntityFramework Core. Therefore i created a base class which adds some basic functionallity to entities. My goal is to achieve a entity handling which can be done with the entity classes exclusively.
This Example should create a User and set the fields Then it should automatically save the changes:
new User()
{
Email = "test123#abc.com",
PwdHash = "some-hash"
}
I already created a base class for that to handle such actions in background:
public abstract class Entity<T> where T : Entity<T>
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public static T Find(params object[] keyValues)
{
var dc = EntityManager.GetContext();
return dc.Find<T>(keyValues);
}
public static List<T> Find(Expression<Func<T, bool>> _condition)
{
var dc = EntityManager.GetContext();
return dc.Set<T>().Where(_condition).ToList();
}
public void Delete()
{
var dc = EntityManager.GetContext();
dc.Set<T>().Remove((T)this);
dc.SaveChanges();
}
public void Commit()
{
var dc = EntityManager.GetContext();
dc.SaveChanges();
}
}
EntityManager simply maintains a DbContext which is working quite fine.
the Entity class is working quite fine too, but i need a way of getting notified on when a property of the subclass (T) is beeing changed to invoke the "Commit()" method.
Currently i am using the property setter:
public class User : Entity<User>
{
[Required]
public string Email {
get => _email;
set { _email = value; Commit(); }
}
private string _email = "";
[Required]
public string PwdHash {
get => _pwdHash;
set { _pwdHash = value; Commit(); }
}
private string _pwdHash = "";
}
But that is not what i want. I would like to simply create a automated property which gets that Commit method appended by the base class automatically. Is that in anyway possible?
Related
6 Years have passed since this question was made and I was expecting to have an easy solution today.. but seems not.
NOTE: please read the other question to understand the concept:
After a few minutes I tried to implement an easy example and I've almost accomplished it. Meanwhile I still see some problems. And I was wondering if someone has ideas on how to make it better.
Using .NET 6 (code bellow).
Issue 1: I don't like the fact that the generics where we say, use TTarget as User, we also need to pass the T ID type.... why by passing User is not enought for the compiler to know the ID data type? Example: class UserService : IBaseDBOperation1<User, Guid> why not class UserService : IBaseDBOperation1<User> ?
Issue 2: I understand that now we are allowed to have interfaces with methods with code, but why do we still need to define the variable type exactly with both data types and using var is not enough? Well, we can use var, but then the methods are not visible.
instead of: IBaseDBOperation1<User, Guid> serviceU1 = new UserService(); ........ var serviceU2 = new UserService(); ...... this second variable will not see the other methods.
Final note: Everything would be so much easier if C# would allow us to extend a class with more than one other abstract class.... (as of today we are limited to 1).
Objective: Accomplish what was asked in the question made 6 years ago.... in other words.... avoid copy/paste, and somehow "inject/associate/register/define" more than one "operation class" into a service.... those "operation classes" will be reused a lot in multiple different services.... and I do want to have a "clean/pretty" way of setting this up, but at the same time, the consumer should not worry about "lower/deeper "lever inheritance generics.
Code
public abstract class BaseDBEntry<T> where T : struct
{
protected BaseDBEntry()
{
CreatedOn = DateTime.Now;
}
public T Id { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime? DeletedOn { get; set; }
}
public class User : BaseDBEntry<Guid>
{
public User() { Id = Guid.NewGuid(); }
public string Name { get; set; }
}
public class Color : BaseDBEntry<long>
{
public Color() { Id = DateTime.Now.Ticks; }
public string RGB { get; set; }
}
Services
public interface IBaseDBOperation1<in TTarget, out T>
where TTarget : BaseDBEntry<T> where T : struct
{
public bool IsValid(TTarget model) { return true; }
T GiveMeId(TTarget model) { return model.Id; }
}
public interface IBaseDBOperation2<in TTarget, T>
where TTarget : BaseDBEntry<T> where T : struct
{
public bool IsValidToDoSomethingElse(TTarget model) { return false; }
}
public class UserService : IBaseDBOperation1<User, Guid>, IBaseDBOperation2<User, Guid> { }
public class ColorService : IBaseDBOperation1<Color, long>, IBaseDBOperation2<Color, long> { }
Consumer
public class Consumer
{
public void Run()
{
IBaseDBOperation1<User, Guid> serviceU1 = new UserService();
IBaseDBOperation2<User, Guid> serviceU2 = new UserService();
var u = new User { Name = "Carl" };
var resU1 = serviceU1.IsValid(u);
var resU2 = serviceU1.GiveMeId(u);
var resU3 = serviceU2.IsValidToDoSomethingElse(u);
var serviceU3 = new UserService();
//serviceU3.XXXXX() --> has no information about the methods we need
IBaseDBOperation2<Color, long> serviceC1 = new ColorService();
var c = new Color { RGB = "#FFFFFF" };
var resC1 = serviceC1.IsValidToDoSomethingElse(c);
var adasda = "";
}
}
var consumer = new Consumer();
consumer.Run();
I will start with small remark - please try to follow standard naming conventions, in this case this one:
Interface names start with a capital I.
As for the issues:
Issue 1: I don't like the fact that the generics where we say, use TTarget as User, we also need to pass the T ID type.
Not much has changed here for the last 6 years, interface BaseDBOperation1<TTarget, T>.. still requires 2 generic type parameters and you can still have an interface with one type parameter, i.e. interface BaseDBOperation1<TTarget> which will be ambiguous for the compiler (so adding interface BaseDBOperation1<TTarget> will become a breaking change, which is a concern if those classes are distributed as library).
Possibly something like this could be achieved with something like higher-kinded types or similar language feature but ATM it is not available in C#.
Related issues to track:
First-class generic method / First-class polymorphism / Rank-N types
Higher Kinded Polymorphism / Generics on Generics
"Opaque" parameters
Existential types for interfaces and abstract types
partial type inference
Issue 2: ... this second variable will not see the other methods.
This is by design (default interface methods draft spec):
Note that a class does not inherit members from its interfaces; that is not changed by this feature:
interface IA
{
void M() { WriteLine("IA.M"); }
}
class C : IA { } // OK
new C().M(); // error: class 'C' does not contain a member 'M'
In order to call any method declared and implemented in the interface, the variable must be the type of the interface
i.e. for var serviceU2 = new UserService(); you will need to cast to corresponding interface:
var resU1 = ((BaseDBOperation1<User, Guid>)serviceU2).IsValid(u);
Another reason for such behaviour can be similar to the so called brittle/fragile base class problem.
Personally I'm not a big fan of this feature both conceptually and due to some corner cases (for example this one).
As for an approach to implement such functionality and reducing code written manually (if you have A LOT of such repositories) - you can look at some compile time code generation with source generators but this is not definitely an easy option. At least for the first time.
Would the following work for you? Essentially making the User and the Color the holder of the service operations.
https://dotnetfiddle.net/zsjZfQ
using System;
var user = new User();
var color = new Color();
Console.WriteLine(user.DbOperation1.IsValid());
Console.WriteLine(user.DbOperation2.IsValidToDoSomethingElse());
Console.WriteLine(user.DbOperation3.ThisIsOnlyAvailableToSome());
Console.WriteLine(color.DbOperation1.IsValid());
Console.WriteLine(color.DbOperation2.IsValidToDoSomethingElse());
var userAsBaseDbEntry = (BaseDBEntry<Guid>)user;
Console.WriteLine(userAsBaseDbEntry.DbOperation1.IsValid());
Console.WriteLine(userAsBaseDbEntry.DbOperation2.IsValidToDoSomethingElse());
public abstract class BaseDBEntry<T> where T : struct
{
public abstract IDbOperation1<T> DbOperation1 { get; init; }
public abstract IDbOperation2<T> DbOperation2 { get; init; }
public T Id { get; init; }
public DateTime CreatedOn { get; init; } = DateTime.Now;
public DateTime? DeletedOn { get; init; }
}
public class User : BaseDBEntry<Guid>
{
public string Name { get; init; }
override public sealed IDbOperation1<Guid> DbOperation1 { get; init; }
override public sealed IDbOperation2<Guid> DbOperation2 { get; init; }
public IDbOperation3 DbOperation3 { get; }
public User()
{
DbOperation1 = new DbOperation1Impl<Guid>(this);
DbOperation2 = new DbOperation2Impl<Guid>(this);
DbOperation3 = new DbOperation3Impl(this);
Id = Guid.NewGuid();
}
}
public interface IDbOperation3
{
bool ThisIsOnlyAvailableToSome();
}
public class DbOperation3Impl : IDbOperation3
{
private readonly BaseDBEntry<Guid> _entry;
public DbOperation3Impl(BaseDBEntry<Guid> entry)
{
_entry = entry;
}
public bool ThisIsOnlyAvailableToSome() => !_entry.DbOperation1.IsValid();
}
public class Color : BaseDBEntry<long>
{
override public sealed IDbOperation1<long> DbOperation1 { get; init; }
override public sealed IDbOperation2<long> DbOperation2 { get; init; }
public string Rgb { get; init; }
public Color()
{
DbOperation1 = new DbOperation1Impl<long>(this);
DbOperation2 = new DbOperation2Impl<long>(this);
Id = DateTime.Now.Ticks;
}
}
public interface IDbOperation1<T> where T : struct
{
bool IsValid();
}
public interface IDbOperation2<T> where T : struct
{
bool IsValidToDoSomethingElse();
}
class DbOperation1Impl<T> : IDbOperation1<T> where T : struct
{
private readonly BaseDBEntry<T> _entry;
public DbOperation1Impl(BaseDBEntry<T> entry)
{
_entry = entry;
}
public bool IsValid() => _entry.CreatedOn < DateTime.Now;
}
class DbOperation2Impl<T> : IDbOperation2<T> where T : struct
{
private readonly BaseDBEntry<T> _entry;
public DbOperation2Impl(BaseDBEntry<T> entry)
{
_entry = entry;
}
public bool IsValidToDoSomethingElse() => _entry.DeletedOn != null;
}
I have a business model TodoItem. I have an API that gives me todoitems. So, I have a corresponding TodoItemModel for each controller (let's name it TodoItemDTO).
The TodoItemDTO class should be able to load itself from a TodoItem business class. So, usually, we would write a static method on the TodoItemDTO class TodoItemDTO FromTodoItem(TodoItem todoItem).
I would like to define an interface for such classes. But unfortunately I can't define a static method in an interface... (note: I use the latest C# version, so, finally, I do, but I should define it... however each class should define its static method)
Here is what I tried:
public interface IDtoModel<TBussinesModel, TDtoModel>
{
TDtoModel FromBusinessModel(TBussinesModel businessObject);
}
public class ToDoItemDTO : IDtoModel<ToDoItem, ToDoItemDTO>
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
public string Description { get; set; }
public bool IsDone { get; private set; }
public ToDoItemDTO FromBusinessModel(ToDoItem businessObject)
{
return new ToDoItemDTO()
{
Id = businessObject.Id,
Title = businessObject.Title,
Description = businessObject.Description,
IsDone = businessObject.IsDone
};
}
}
The only 'problem' here is I have a class method that should be, normally, a static method.
So, by eg, when I define a generic controller, I need to create new objects without any need:
[Route("api/[controller]")]
[ApiController]
public abstract class BaseApiController<TBussinesModel, TDtoModel> : Controller
where TBussinesModel : BaseEntity
where TDtoModel : IDtoModel<TBussinesModel, TDtoModel>, new()
{
protected readonly IRepository _repository;
public BaseApiController(IRepository repository) { _repository = repository; }
[HttpGet("{id:int}")]
public async Task<IActionResult> GetById(int id)
{
var businessObject = await _repository.GetByIdAsync<TBussinesModel>(id);
//
// here bellow, I need to create a new object
//
var dtoObject = (new TDtoModel()).FromBusinessModel(businessObject);
return Ok(dtoObject);
}
[HttpPost]
public abstract Task<IActionResult> Post([FromBody] TDtoModel item);
}
There are lots of options, none of them perfect.
Personally, I would start by turning your factory method into a constructor of the DTO;
public ToDoItemDTO(ToDoItem businessObject)
{
Id = businessObject.Id;
Title = businessObject.Title;
Description = businessObject.Description;
IsDone = businessObject.IsDone;
}
You could define a factory class for each DTO. You could use Activator.CreateInstance to dynamically call the constructor at runtime.
Or you can locate the constructor with reflection, build an Expression tree and compile it.
static Func<TBussinesModel, TDtoModel> GetFactory<TBussinesModel, TDtoModel>()
{
var p = Expression.Parameter(typeof(TBussinesModel), "p");
return Expression.Lambda<Func<TBussinesModel, TDtoModel>>(
Expression.New(
typeof(TDtoModel).GetConstructor(new Type[] { typeof(TBussinesModel) }),
p
),
p)
.Compile();
}
I am not sure in terms of exact technical specification for this problem to me but in simple words I am trying to create a wrapper/extension method around to save my entities.
So I added new Entity Data Model (.edmx) file to my project. That generates DbSet(s) like this-
public partial class SUContextContainer : DbContext
{
public SUContextContainer()
: base("name=SUContextContainer")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public DbSet<Category> Categories { get; set; }
public DbSet<Gallery> Galleries { get; set; }
public DbSet<SuperUser> SuperUsers { get; set; }
public DbSet<UserType> UserTypes { get; set; }
}
Now here I am trying to wrap this into an extension method for database operations like (save, delete, update etc..)
I tried creating it as -
public static void Save(this EntityObject objEntity)
{
try // Update Record
{
((IObjectContextAdapter)Global.Context).ObjectContext.ObjectStateManager.ChangeObjectState(objEntity, EntityState.Modified);
Global.Context.SaveChanges();
}
catch (OptimisticConcurrencyException) // Insert Record
{
((IObjectContextAdapter)Global.Context).ObjectContext.ObjectStateManager.ChangeObjectState(objEntity, EntityState.Added);
Global.Context.SaveChanges();
}
}
This method is attached to EntityObject types. Where .edmx code which it generates are of type DbContext.
So Whenever I try to save some entity with this helper method it never finds out.
var galleryEntity = new Gallery {
IsActive = true,
CategoryId = model.CategoryId,
};
galleryEntity.Save(); // the save method is not found.
I tried above method to change in -
public static void Save(this DbSet objEntity)
But this also doesn't seem to take as extension method.
What am I doing wrong.
So Whenever I try to save some entity with this helper method it never
finds out.
It will not, because gallery is just a class and is not inherited from EntityObject.
I don't suggest adding inheritence or modifiying autogenerated classes.
Use power of partial classes:
You can create patial classess for your models with interface.
public partial class Gallery : IEntity
{
//This is your class different than auto generated class by Ef.
}
Also you shouldn't use try catch for decision. That's why you should seperate update and create and make decision on upper level (without try catch).
So your extension methods should be like this.
public static int Update<T>(this T entity) where T : IEntity
{
using(var dbContext=new SUContextContainer())
{
var entry = dbContext.Entry(entity);
dbContext.Set<T>().Attach(entity);
entry.State = EntityState.Modified;
return dbContext.SaveChanges();
}
}
public static int Create<T>(this T entity) where T : IEntity
{
using(var dbContext=new SUContextContainer())
{
dbContext.Set<T>().Add(entity);
return dbContext.SaveChanges();
}
}
Your extension method will only apply to types that inherit from EntityObject.
You will either need to make all of your entity classes inherit from this EntityObject class or create another extension method that applies to the correct type.
Typically when using these kind of persistence patterns you would create an entity base class
public class Entity
{
public int Id { get; set; }
}
and each entity type inherits from it
public class Gallery : Entity
{
public int Name { get; set; }
}
Then you can have common methods that you use across entity types:
public static void Save(this Entity entity);
I have two versions of a factory class designed based on the article
http://www.oodesign.com/factory-pattern.html
public abstract class Employee
{
public string Name { get; set; }
protected string Role { get; set; }
public abstract string GetRole();
}
public class Manager : Employee
{
public Manager()
{
Role = "MGR";
}
public override string GetRole()
{
return this.Role;
}
}
Version 1: Simple, Violates Open Close Principle
Need to change SimpleEmployeeFactory every time, when I add a new concrete class
public class SimpleEmployeeFactory
{
public static Employee GetEmployee(int typeId)
{
switch (typeId)
{
case 1:
return new Manager();
case 2:
return new TechnicalLead();
default:
return null; //if the id doesn't have any
}
}
}
Version 2:
Refactored Factory, still needs a Concrete Class creation, before we use factory call
public abstract class Employee
{
public string Name { get; set; }
protected string Role { get; set; }
public abstract string GetRole();
public abstract Employee createEmployee();
}
public class ChiefTechnologyOfficer : Employee
{
public ChiefTechnologyOfficer()
{
this.Role = "CTO";
}
static ChiefTechnologyOfficer()
{
RefactoredFactory.Instance.registerEmployee(5, new ChiefTechnologyOfficer());
}
public override string GetRole()
{
return this.Role;
}
public override Employee createEmployee()
{
return new ChiefTechnologyOfficer();
}
}
Factory
class RefactoredFactory
{
private static readonly RefactoredFactory instance = new RefactoredFactory();
static RefactoredFactory()
{
}
private RefactoredFactory()
{
}
public static RefactoredFactory Instance
{
get
{
return instance;
}
}
private Dictionary<int, Employee> registeredEmployees = new Dictionary<int, Employee>();
public void registerEmployee(int typeId, Employee employeeInst)
{
registeredEmployees.Add(typeId, employeeInst);
}
public Employee createEmployee(int typeId)
{
return ((Employee)registeredEmployees[typeId]).createEmployee();
}
}
Client
Employee emp = SimpleEmployeeFactory.GetEmployee(1);
Activator.CreateInstance(typeof(ChiefTechnologyOfficer)); //Avoid
Employee empFNoR = RefactoredFactory.Instance.createEmployee(5);
You can see Activator.CreateInstance(typeof(ChiefTechnologyOfficer)) call to make the concrete classes to register themselves with the Factory. Otherwise we cant retrieve the object
Is there a way to create a Factory class with out violating OCP principle & with out creating an object like the one I used in RefactoredFactory class?
It looks like the typeId suffers from Feature Envy. Instead, define a polymorphic type to capture the type; e.g. an interface:
public interface IEmployeeType
{
Employee Create()
}
Now you can define e.g. a ManagerType, and a TechnicalLeadType, etc. Example:
public class ManagerType : IEmployeeType
{
public Employee Create()
{
return new Manager();
}
}
This is essentially an Abstract Factory, and it has the advantage that you can always create a new implementation when you need to create a new sub-type.
If you're at the boundary of a system, and must translate a primitive value like an integer to a polymorphic value, you can use one of the Role Hint patterns - particularly Metadata, Role Interface, or (my favourite) Partial Type Name.
Client
Given an IEmployeeType instance employeeType, a client would simply go:
Employee emp = employeeType.Create();
Thala,
Instead of using static constructor,register method to populate dictionary of Types.
You can use config based solution like .net DbProviderFactory, to register all types.
<EmployeeFactories>
<add name="manger" type="Manager, EmployeeAssmbly" />
..
</EmployeeFactories>
I'm designing a data layer for several classes, and I want each of these classes to follow a contract I set up with IMyDataItem:
public delegate void ItemChangedHandler(object sender, EventArgs e);
public interface IMyDataItem<T> {
string Insert { get; }
int Save();
string Select { get; }
string Update { get; }
}
That being done, I now want to include a base class that my other classes all inherit from.
How would I fix this base class?
public class MyDataItem : IMyDataItem<T> {
private const string TODO = "TODO: This has not been done.";
public const int NOT_SET = -1;
private bool changed;
internal int rowId;
public MyDataItem() {
changed = false;
rowId = NOT_SET;
}
public ItemChangedHandler OnChange;
internal void notify() {
changed = true;
if (OnChange != null) {
OnChange(this, new EventArgs());
}
}
public int RowID {
get { return rowId; }
set {
if (rowId != value) {
rowId = value;
notify();
}
}
}
public bool SaveNeeded { get { return changed; } }
public static virtual T Load() {
return default(T);
}
public virtual string Insert { get { return TODO; } }
public virtual string Select { get { return TODO; } }
public virtual string Update { get { return TODO; } }
public virtual int Save() {
changed = false;
return NOT_SET;
}
}
The errors are all in the second class MyDataItem (my base class):
Type or namespace name 'T' could not be found - on the first line where I declare my class.
I tried removing the errors by adding a where clause to the signature:
public class MyDataItem : IMyDataItem<T> where T : MyDataItem {
However, this presented me with the error:
Constraints are not allowed on non-generic declarations
Is there a way to do what I am after, or will I need to stick with simpler class designs?
When the base class is complete, other classes such as Location, Employee, and Record will inherit it.
Well to fix that particularly compile time error you would need:
public class MyDataItem<T> : IMyDataItem<T>
However, without knowing more about what you're trying to achieve, it's hard to recommend an alternative approach.
Why not drop the <T> from the interface and make it non-generic? The T is not used in the interface.
Otherwise, if you want the class to be generic, say
public class MyDataItem<T> : IMyDataItem<T>
But again, if T is not used, what's your reason to declare it?
What you are attempting to do is somewhat similar to what I've also done. I've wanted some generic code applicable to all my "data manager" instances but also wanted to apply stronger typing to them... In a similar fashion...
public interface iMyDataManager
{
stuff ...
}
public class MyDataManager<T> : iMyDataManager
{
implementation ... that I want common to all derived specific instances
}
public class MySpecificDataInstance : MyDataManager<MySpecificDataInstance>
{
continue with rest of actual implementations specific to this class.
}
I did not see any reason use generic in your implementation.
Secondary, are you sure about parameters of these functions:
string Insert { get; }
int Save();
string Select { get; }
string Update { get; }
Why Update and Insert returns parameters? Are you sure, you will able remember meaning of this within 2 months?