This may be trivial. But I could not able to get my heads over this.
public class Manager
{
public int ID { get; set; }
public List<Employee> Employees { get; set; }
public bool IsAllEmpEngaged { get; set; }
public void UpdateIsAllEmpEngaged()
{
IsAllEmpEngaged = Employees.All(emp => emp.IsEngagedwithWork == true);
}
}
public class Employee
{
public int ID { get; set; }
public bool IsEngagedwithWork { get; set; }
}
So, Whenever, the IsEngagedwithWork of Employee is setted with some value, I want to check whether all the Employees under aManager is Engaged with work or not and update the value of IsAllEmpEngaged of the respective Manager.
I just want to call UpdateIsAllEmpEngaged on changes in property IsEngagedwithWork of Employee. How can I achieve this?
Any other ways are also welcome.
Note: I tried with a having an event on Employee and attach Action from the Manager that will callback if any changes in Employee property. But I will be having hundreds of List<Manager>. I dont want to add event for each and every instance of Employee class. Any easy way?
Update:
I am working with WPF MVVM approach, I cannot use direct get with LinQ as it will not notify the UI. I have to set the property manually for change so that it will Notify the UI.
Also, In actual case, the IsEngagedwithWork will be updated in UI for the property IsEngagedwithWork.
Simple solution is add ManagerId as well to the Employee model class and after your line of code that sets IsEngagedwithWork of the employee instance (say emp), do the below thing
Manager mngr = managers.Select(m => m.ID == emp.ManagerId).FirstOrDefault();
if(mngr != null)
mngr.IsAllEmpEngaged = mngr.IsAllEmpEngaged && emp.IsEngagedwithWork;
I'd use the getter of the property like that
public bool IsAllEmpEngaged {
get {
return (Employees != null) &&
Employees.All(e => e.IsEngagedwithWork)
}
}
and you add the following method for the Manager Class
public void NotifyChanged() { OnPropertyChanged(() => IsAllEmpEngaged }
then you call it from the Employee Class (assuming you have the managers' list or an equivalent way)
private int _ID;
private bool _IsEngagedwithWork;
public int ID {
get { return _ID};
set {
_ID = value;
OnPropertyChanged(()=>ID );
notifyMe = managerList.FirstOrDefualt(m => m.ID == _ID);
if (notifyMe != null) { notifyMe.NotifyChanged()}
}
}
public bool IsEngagedwithWork {
get { return _IsEngagedwithWork ;}
set {
_IsEngagedwithWork = value;
OnPropertyChanged(()=>IsEngagedwithWork );
notifyMe = managerList.FirstOrDefualt(m => m.ID == _ID);
if (notifyMe != null) { notifyMe.NotifyChanged()}
}
}
What i would do :
make IsAllEmpEngaged private
make the collection Empoyess private and add a function that add a new employee:
Add a function that adds a new employee.
And now two choiches :
1) after the employee is added, iterate the collection and update the IsAllEmpEngaged property
public void AddNewEmployee(Employee employee){
this.Employees.Add(employee);
bool all = true;
foreach(Employee emp in this.Employees){
if (!emp.IsEngagedwithWork){
all = false;
break;
}
}
this.IsAllEmpEngaged = all;
}
2)
start with IsAllEmpEngaged = true; when the class is inited and the collection is empty
when the employee is added, update the IsAllEmpEngaged property but keeping count of the last choice (this works only if you don't remove employess)
public void AddNewEmployee(Employee employee){
this.Employees.Add(employee);
this.IsAllEmpEngaged = this.IsAllEmpEngaged && employee.IsEngagedwithWork
}
I can't say that this is any better, but surely this is a simple and easy way.
Why not just make IsAllEmpEngaged a method? You don't even need the set property accessor, so a method should suffice.
public bool IsAllEmpEngaged()
{
if (Employees == null)
{
// throw error
}
return Employees.All(e => e.IsEngagedwithWork);
}
Maybe it work's when you pass your Manager as parameter to Employee and then call your Method if IsEngagedWithWork is set to true.
public class Employee
{
private Manager _parentManager;
public Employee(Manager parentManager)
{
_parentManager=parentManager;
}
public int ID { get; set; }
private bool _isEngangedWithWork;
public bool IsEngagedwithWork
{
get{ return _isEngangedWithWork; }
set
{
_isEngangedWithWork=value;
if(_isEngangedWithWork)
_parentManager.UpdateIsAllEmpEngaged();
}
}
}
Related
I am searching for a solution where i can ask a model if a property has changed. But i want to prevent to write own setter methods for all models and all their properties.
I want to use this to automatically generate a update queries based models and there changed properties. But if my model has a boolean property Test which is by default false, then i can't differentiate if the value is from the request payload or if it is the default value.
I already saw the INotifyPropertyChanged Implementation but there i have to write a setter for all properties too.
public class Main
{
public static void main()
{
var person = new Person();
Console.WriteLine(person.HasChanged("Firstname")); // false
Console.WriteLine(person.HasChanged("Lastname")); // false
Console.WriteLine(person.HasChanged("LikesChocolate")); // false
person.Firstname = "HisFirstname";
person.LikesChocolate = true;
Console.WriteLine(person.HasChanged("Firstname")); // true
Console.WriteLine(person.HasChanged("Lastname")); // false
Console.WriteLine(person.HasChanged("LikesChocolate")); // true
}
}
public class Person : BaseModel
{
public string Firstname { get; set; }
public string Lastname { get; set; }
public bool LikesChocolate { get; set; }
}
public class BaseModel
{
public bool HasChanged(string propertyName)
{
// ...
}
}
I'd probably reuse the idea from WPF with their INotifyPropertyChanged pattern and simplify it a bit for the current needs. However, it resolves the question only partially, as you still need to write setters. But at least, you don't need to manage each property on its own.
So, the solution will be something like this:
void Main()
{
var person = new Person();
Console.WriteLine(person.HasChanged(nameof(Person.FirstName))); // false
Console.WriteLine(person.HasChanged(nameof(Person.LastName))); // false
Console.WriteLine(person.HasChanged(nameof(Person.LikesChocolate))); // false
person.FirstName = "HisFirstname";
person.LikesChocolate = true;
Console.WriteLine(person.HasChanged(nameof(Person.FirstName))); // true
Console.WriteLine(person.HasChanged(nameof(Person.LastName))); // false
Console.WriteLine(person.HasChanged(nameof(Person.LikesChocolate))); // true
}
public class Person : ChangeTrackable
{
private string _firstName;
private string _lastName;
private bool _likesChocolate;
public string FirstName
{
get { return _firstName; }
set { SetProperty(ref _firstName, value); }
}
public string LastName
{
get { return _lastName; }
set { SetProperty(ref _lastName, value); }
}
public bool LikesChocolate
{
get { return _likesChocolate; }
set { SetProperty(ref _likesChocolate, value); }
}
}
public class ChangeTrackable
{
private ConcurrentDictionary<string, bool> _changes =
new ConcurrentDictionary<string, bool>();
public bool HasChanged(string propertyName)
{
return _changes.TryGetValue(propertyName, out var isChanged)
? isChanged : false;
}
public void ResetChanges()
{
_changes.Clear();
}
protected void SetProperty<T>(
ref T storage, T value, [CallerMemberName] string propertyName = "")
{
if (!Equals(storage, value))
{
_changes[propertyName] = true;
}
}
}
The ChangeTrackable tracks if property was changed and does it without any reflection that guarantees high performance. Note, that with this implementation you need to call ResetChanges if you initialize property with some actual values after constructing the object. Drawback is that you need to write each property with its backing field and call SetProperty. On the other side, you decide what to track, that could be handy in the future in your application. Also we don't need to write property as strings (thanks to compile-time CallerMemberName and nameof) that simplifies refactorings.
INotifyPropertyChanged is the established practice for this type of requirement. Part of keeping your code maintainable is by keeping it predictable and by adopting best practices and patterns.
An alternative, which I wouldn't recommend, would be to use reflection to iterate over all of your properties and dynamically add a property changed event handler. This handler could then set a boolean flag which can be returned by your HasChanges method. Please refer to this for a staring point: AddEventHandler using reflection
I would recommend avoiding unnecessary complexity though and stick with PropertyChanged notifications in your setters.
As followup for my comment a proof of concept (online):
using System.Reflection;
public class HasChangedBase
{
private class PropertyState
{
public PropertyInfo Property {get;set;}
public Object Value {get;set;}
}
private Dictionary<string, PropertyState> propertyStore;
public void SaveState()
{
propertyStore = this
.GetType()
.GetProperties()
.ToDictionary(p=>p.Name, p=>new PropertyState{Property = p, Value = p.GetValue(this)});
}
public bool HasChanged(string propertyName)
{
return propertyStore != null
&& propertyStore.ContainsKey(propertyName)
&& propertyStore[propertyName].Value != propertyStore[propertyName].Property.GetValue(this);
}
}
public class POCO : HasChangedBase
{
public string Prop1 {get;set;}
public string Prop2 {get;set;}
}
var poco = new POCO();
poco.Prop1 = "a";
poco.Prop2 = "B";
poco.SaveState();
poco.Prop2 = "b";
poco.HasChanged("Prop1");
poco.HasChanged("Prop2");
Be aware, that reflection may reduce the performance of your application when used extensively.
I have three columns in the db table that looks as follow:
When I add a new row, it should store the value on column fieldname in uppercase. How can I do that?
Since you tagged the question with entity framework, I assume you want to do it in your data layer or close to DB. There's a number of ways for doing this.
You could override SaveChanges() in your context. This will move the logic away from the model, but still ensure that the correct value is saved. Also, if you want it on several entities you can use an interface. When it's an interface you can do it for several of your entities without any duplicate code, as long as it's the same property. Otherwise you would need an attribute and reflection. Reusability is pretty high, but it adds some overhead to your SaveChanges().
public class CustomerEntity()
{
public string Name {get;set;}
}
public MyCustomContext : DbContext
{
// Other stuff...
public override int SaveChanges()
{
foreach (var entry in ChangeTracker.Entries<CustomerEntity>())
{
if (entry.State == EntityState.Modified || entry.State == EntityState.Added)
{
// Possibly check for null or if it's changed at all.
entry.Entity.Name = entry.Entity.Name.ToUpper();
}
}
return base.SaveChanges();
}
}
And with an interface:
public interface INameIsAlwaysUpperCase
{
string Name {get;set;}
}
public MyCustomContext : DbContext
{
// Other stuff...
public override int SaveChanges()
{
foreach (var entry in ChangeTracker.Entries<INameIsAlwaysUpperCase>())
{
if (entry.State == EntityState.Modified || entry.State == EntityState.Added)
{
// Possibly check for null or if it's changed at all.
entry.Entity.Name = entry.Entity.Name.ToUpper();
}
}
return base.SaveChanges();
}
}
You can add a custom validation. This will throw exception if it's not saved correctly. That way you can move the responsibility to the consumer of the model. However, depending on your scenario, you might not want to throw an exception. This is my favourite since it forces the consumer to do it the right way. As per comments, why throw when you can silently convert it? Yes, it's a valid question. For me it's about forcing the consumer of the data layer to use it correctly, and not let the daya layer decide what to to with the data. I personally don't like it when the business layer asks the data layer to save one thing, and then the data layer saves another thing. If lower case isn't a valid option, then it shouldn't be saved. I don't think it's much more different from using [Required]. But it's really about context and what works in your particular case.
public class CustomerEntity() : IValidatableObject
{
public string Name {get;set;}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// Possibly check for null here as well...
if (this.Name.ToUpper() != this.Name)
{
yield return new ValidationResult("You need to save as upper!");
}
}
}
Use a property that manages this for you. This may be the simplest solution, even if I like to keep my entities "clean". It's absolutely the solution that will require least effort. However, the reusability is low, and what if you use your entitites all over the application and want the value to be lower case until it's actually saved? That's not possible. But, again, I think it comes down to your particular situation. If you want the value to be upper case even before you save it, this is probably the best solution!
public class CustomerEntity()
{
string _name;
public string Name
{
get { return _name; }
set { _name = value.ToUpper(); } // Check for null ?
}
}
Do it when saving. This moves the logic to when you're saving your entity. This is probably the least preferable option, since the reusability is non-existing. What happens in Update()? However, the OP specifically states "When I add a new row", so it may only be applicable when adding new entities. And in that case it could very well be the most prefered choice since it allows updates to have lower case. But it would have to depend on the use case.
public void AddCustomer(string name)
{
var customer = new CustomerEntity
{
Name = name.ToUpper()
};
_context.Customers.Add(customer);
}
Just use properties. If your model is as below:
public class MyModel
{
public int Id { get; set; }
public string Description { get; set; }
public string LanguageCode { get; set; }
public string FiledName { get; set; }
}
Then, change it to:
public class MyModel
{
private string fieldName;
public int Id { get; set; }
public string Description { get; set; }
public string LanguageCode { get; set; }
public string FiledName
{
get { return filedName; }
set
{
if(!string.IsNullOrEmpty(value))
fieldName = value.ToUpper();
else
fieldName = value;
}
}
}
Try this.
public string FiledName
{
get { return filedName; }
set
{
filedName = !string.IsNullOrEmpty( value ) ? value.ToUpper() : value;
}
}
Using a ValueConverter on the Property could be an effective way to do this.
public class YourDbContext : DbContext
{
public YourDbContext(DbContextOptions<YourDbContext> options)
: base(options)
{
}
public DbSet<Row> Rows { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
var converter = new ValueConverter<string, string>(
v => v.ToUpper(), // writing
v => v
);
// just one property
modelBuilder.Entity<Row>()
.Property(x => x.Column)
.HasConversion(converter);
// all of the string properties
foreach (var entityType in builder.Model.GetEntityTypes())
{
foreach (var property in entityType.GetProperties())
{
if (property.ClrType == typeof(string))
{
builder.Entity(entityType.Name)
.Property(property.Name)
.HasConversion(converter);
}
}
}
}
}
It's also possible to use a Custom Attribute :
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class Standardized : Attribute
{}
Then decorate properties inside your model :
public class MyModel
{
public string Id{ get; set; }
[Required]
[Standardized]
public string Description { get; set; }
}
Taken from #smoksnes accepted answer, inside your DbContext class, override SaveChanges(), SaveChangesAsync() (EF Core 5.x) and add a private method using reflection to obtain decorated properties and apply transformations, like this :
public override int SaveChanges()
{
StandardizeBeforeSaving();
return base.SaveChanges();
}
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
StandardizeBeforeSaving();
return await base.SaveChangesAsync(cancellationToken);
}
private void StandardizeBeforeSaving()
{
foreach (var entry in ChangeTracker.Entries())
{
if (entry.State == EntityState.Modified || entry.State == EntityState.Added)
{
var properties = entry.Entity
.GetType()
.GetProperties()
.Where(prop => Attribute.IsDefined(prop, typeof(Standardized)) && prop.PropertyType == typeof(string));
foreach (var property in properties)
{
var value = entry.CurrentValues[property.Name]?.ToString() ?? string.Empty;
entry.CurrentValues[property.Name] = value.Standardize();
}
}
}
}
Just be aware that reflection could be slower than other techniques presented in accepted answer. But for most scenarios (ie. user updates or creates couple of entities with not that many properties) it should be fine.
I have class which have too many related calculated properties.
I have currently kept all properties are read only.
some properties need long calculation and it is called again when its related properties are needed.
How can create this complex object .Also i want these properties should not be set from external code. I need show hide as i am binding properties for UI. Also i think order is also important.
My Class is something like
public string A
{
get
{
return complexMethod();
;
}
}
public string B
{
get
{
if (A == "value")
return "A";
else return "B";
;
}
}
public bool ShowHideA
{
get
{
return string.IsNullOrEmpty(A);
;
}
}
public bool ShowHideB
{
get
{
return string.IsNullOrEmpty(B);
;
}
}
public string complexMethod()
{
string value = "";
// calculation goes here
return value;
}
}
Thanks
You need to use Lazy type provided by .net:
Lazy<YourType> lazy = new Lazy<YourType>();
Make your properties internal to not be set from external code.
Well tall order isn't it?
One of the coolest things about extension methods is you can use types. This is perfect for writing external programs to calculate property values. Start like this...
public static class XMLibrary
{
public static MC CalculateValues(this MC myclass)
{
//for each property calculate the values here
if (myclass.Name == string.Empty) myclass.Name = "You must supply a name";
if (myclass.Next == 0) myclass.Next = 1;
//when done return the type
return myclass;
}
}
public class MC
{
public string Name { get; set; }
public int Next { get; set; }
}
public class SomeMainClass
{
public SomeMainClass()
{
var mc = new MC { Name = "test", Next = 0 };
var results = mc.CalculateValues();
}
}
There are many other ways to do class validation on a model, for example dataannotations comes to mind, or IValidatableObject works too. Keeping the validation separate from the class is a good idea.
//Complex properites are simple
public class MyComplextClass{
public List<MyThings> MyThings {get;set;}
public List<FileInfo> MyFiles {get;set;}
public List<DateTime> MyDates {get;set;}
}
I have two interfaces and the both have the same exact properties.
Just in case you're wondering why I've got two interfaces like these it's a long story, but yes, it has to be this way.
Based on a condition a List is returned if condition is the other way a List will be returned.
By looking at my interfaces and my code below I need to be able to make use of one object, in other words if doesn't matter which interface is returned I need to be able to work with one object and not looping one List interface and setting properties of the other.
I need something like this
compParts = genCompParts;
--- Code usage
public class ComponentParts : IComponentParts
{
public ComponentParts() { }
public ComponentParts(Guid userID, int compID, bool isGeneric)
{
List<IComponentPart> compParts = null;
List<IComponentPart_Max> genCompParts = null;
if (isGeneric)
{
genCompParts = GenericCatalogBL.GenericCatalogManagerBL.GetComponentPartsMax(compID);
}
else
{
compParts = CatalogManagerDL.GetComponentParts(userID, compID);
}
var verParts = compParts.Where(x => x.CompTypeName.ToLower().Contains("vertical"));
if (verParts.Count() > 0) { this.Vertical = verParts.ToList<IComponentPart>(); }
var horParts = compParts.Where(x => x.CompTypeName.ToLower().Contains("horizontal"));
if (horParts.Count() > 0) { this.Horizontal = horParts.ToList<IComponentPart>(); }
//... redundant code omitted
---Interface Snapshots---
I ended up creating a class library call Interfaces and I just share those interfaces across different programs in my solution.
It's what I should of done in the first place, just being lazy.
The totally brute-force way, assuming you don't own either IComponentPart or IComponentPart_Max and can't fix one of them.
Make a new interface that you control
interface IComponentPart {
string BrandGroup {get; set;}
int BrandID {get; set;}
// ...
}
Make wrappers for both of the existing interfaces that adapt them to your interface
class IComponentPartWrapper : IComponentPart {
private readonly CatelogDL.IComponentPart _underlyingPart;
public IComponentPartWrapper(CatelogDL.IComponentPart underlyingPart) {
_underlyingPart = underlyingPart
}
public string BrandGroup {
get {return _underlyingPart.BrandGroup;}
set {_underlyingPart.BrandGroup = value;}
}
public int BrandID {
get {return _underlyingPart.BrandID ;}
set {_underlyingPart.BrandID = value;}
}
// ...
}
class IComponentPart_MaxWrapper : IComponentPart {
private readonly GenericCatalogDL.IComponentPart_Max _underlyingPart;
public IComponentPartWrapper(GenericCatalogDL.IComponentPart_Max underlyingPart) {
_underlyingPart = underlyingPart
}
public string BrandGroup {
get {return _underlyingPart.BrandGroup;}
set {_underlyingPart.BrandGroup = value;}
}
public int BrandID {
get {return _underlyingPart.BrandID ;}
set {_underlyingPart.BrandID = value;}
}
// ...
}
Make your code use your interface, and wrap the results from either library in the corresponding wrapper
public class ComponentParts : IComponentParts
{
public ComponentParts() { }
public ComponentParts(Guid userID, int compID, bool isGeneric)
{
List<IComponentPart> compParts;
if (isGeneric)
{
compParts = GenericCatalogBL.GenericCatalogManagerBL.GetComponentPartsMax(compID)
.Select(x => new IComponentPart_MaxWrapper(x))
.ToList();
}
else
{
compParts = CatalogManagerDL.GetComponentParts(userID, compID)
.Select(x => new IComponentPartWrapper(x))
.ToList();
}
// ...
I'm currently working on a solution that has a set of composite ViewModels that are mapped from domain models coming back from a set of data access services.
So far I've had a good amount of success with implementing INotifyPropertyChanged on the base ViewModel object and notifying the UI of changes to the property objects via property changed events.
Here's an example of a view model:
public class DisplayDataModel : INotifyPropertyChanged{
private DateTime _lastRefreshTime;
public DateTime LastRefreshTime {
get { return _lastRefreshTime; }
set {
_lastRefreshTime = value;
this.NotifyPropertyChanged(lddm => lddm.LastRefreshTime, PropertyChanged);
}
}
private string _lineStatus;
public string LineStatus {
get { return _lineStatus; }
set {
if (_lineStatus != value) {
_lineStatus = value;
this.NotifyPropertyChanged(lddm => lddm.LineStatus, PropertyChanged);
}
}
}
private ProductionBrickModel _productionBrick;
public ProductionBrickModel ProductionBrick {
get { return _productionBrick;}
set {
if (_productionBrick != value) {
_productionBrick = value;
this.NotifyPropertyChanged(lddm => lddm.ProductionBrick, PropertyChanged);
}
}
}
}
public class ProductionBrickModel{
public int? Set { get; set; }
public int? Theoretical { get; set; }
public int? Actual { get; set; }
public string LineName { get; set; }
public TimeSpan? ShiftOverage { get; set; }
public SolidColorBrush ShiftOverageBrush {
get {
if (ShiftOverage.HasValue && ShiftOverage.Value.Milliseconds < 0) {
return Application.Current.FindResource("IndicatorRedBrush") as SolidColorBrush;
}
return Application.Current.FindResource("IndicatorWhiteBrush") as SolidColorBrush;
}
}
public string ShiftOverageString { get { return ShiftOverage.HasValue ? ShiftOverage.Value.ToShortTimeSpanString() : ""; } }
}
So currently I'm firing notification events on the base model and not the production brick property, mostly because the production brick properties will be changing almost every refresh anyways.
Recently I've started cranking refresh times down to around 350ms and I'm seeing situations where the ShiftOverageBrush is changing to white for a split second even though the values are still negative.
My question is by going through and implementing INotifyPropertyChanged on the object types that make up the base view model will I gain any performance, or even possibly solve this issue? Or is this coming from something else entirely that I'm not understanding?
There are two obvious sources of inefficieny in your code:
1) ShiftOverageBrush is using FindResource every time it's called. Why not cache the brushes?
private SolidColorBrush _redBrush;
private SolidColorBrush IndicatorRedBrush
{
get{ return _redBrush ?? (_redBrush =
Application.Current.FindResource("IndicatorRedBrush") as SolidColorBrush));
}
... same for white brush
public SolidColorBrush ShiftOverageBrush {
get {
if (ShiftOverage.HasValue && ShiftOverage.Value.Milliseconds < 0) {
return IndicatorRedBrush;
}
return IndicatorWhiteBrush;
}
}
2) Using a lambda expression for NotifyPropertyChanged is convenient but is pretty slow since it uses reflection. If you're cranking up the update rate, then replace the lambdas with strings.