I want to provide predefined filters for displaying search results. The filter is more or less stored as an expression tree and can be constructed using a rule editor.
I want to provide the user with an editor, select a property, select the operator and allow the user to provide or select a value to compare with.
[dropdown with properties = PriorityId] [dropdown with operators = Equals] [dropdown with values = IList()]
The challenge is that the user needs to get a list of values to select from and I am figuring out how to
I have thought about the following approach, and I would like to get your input on this.
Decorate the property with an attribute
The attribute maps a class responsible for returning possible values
The mapping class implements an interface
When selecting the property from the rule editor I can execute an ajax call to a supporting controller to get the values back. In this controller I can invoke the mapping class via reflection to return the values.
namespace Tickets.Data.Model
{
public class Ticket : BaseModel
{
[RuleEditorCollectionMapping(typeof(GetPriorities))]
public string PriorityId { get; set; }
}
}
public class RuleEditorCollectionMappingAttribute : Attribute
{
private Type classType;
public RuleEditorCollectionMappingAttribute(Type classType)
{
this.classType = classType;
}
}
public interface IRuleEditorCollectionMapping{}
public class GetPriorities : IRuleEditorCollectionMapping
{
public static IList<TicketPriority> GetValues()
{
// query logic to build a list with values to be used in the rules editor when selecting PriorityId
return new List<TicketPriority>();
}
}
Questions:
Is my approach a viable one? More or less a sanity check so I don't take the wrong turn.
If not, do you have any other suggestions or guidance from experience to approach this situation?
Related
I have data from multiple organisations (police, fire, office) that need output in different formats.
To achieve this, I defined the following (this is a little simplified):
Transaction class -
"Success" indicator - Boolean.
"Type of department"- String or Enum.
A class which can be of any type - Police, Fire or Office (My question is on this as you will see).
A GenerateOutput() method - to handle generation of file formats.
Police class
Age - String
VehicleNumber - Integer
Supervisor - String
Fire class
Name - String
FireEngineNumber - Integer
County - Enum
WorkTimings - Enum
Office Class
Age - String
DeskNumber - Integer
Department - String
PayScale - Enum
IsManagement - Bool
As you can see, the Police, Fire and Office classes dont share anything in common and are primarily intended as data carrying entities. I intend to use a Factory to return an appropriate generic (not a C# generic) Transaction object with the data (Transaction object with Police, Fire or Office data within it) and then pass the returned object to a Strategy pattern which determines the file format (CSV, Excel, or XML; specified in a configuration file) each one needs.
My problem is in the definition of the Transaction object.
What type does the class in "3." of the Transaction class need to be? The data for each org differs, there are no common members, I am unable to define a common class for all.
Is the overall design appropriate? What other designs should I consider?
Based on Peter's comments below:
I think using generics might work, I ran into a problem though. I would like to use a factory to return the object requested, using GetTransactionObject, as below. What should be the return type of GetTransactionObject to accomodate this.
class TransactionFactory
{
Dictionary<string, Type> typeClassLookup;
public TransactionFactory()
{
typeClassLookup = new Dictionary<string, Type>();
typeClassLookup.Add("Police", typeof(PoliceData));
typeClassLookup.Add("Fire", typeof(FireData));
}
Transaction<????> GetTransactionObject(string org)
{
if( typeClassLookup.TryGetValue(org, out typeValue))
{
switch (typeValue.ToString())
{
case "policeData":
transactionObject = new Transaction<PoliceData>() { Data = new PoliceData(), params = null};
case "FireData":
transactionObject = new Transaction<FireData>() {Data = new FireData(), params = null};
}
}
return transactionObject;
If the types really have nothing in common, then you need no explicit base class. System.Object suffices, just as with many other generic types (i.e. any generic type lacking a constraint).
In other words, you could declare as:
class Transaction<T>
{
public bool Success { get; private set; }
public T Entity { get; private set; }
public Transaction(bool success, T entity)
{
Success = success;
Entity = entity;
}
public void GenerateOutput() { /* something goes here */ }
}
Personally, I would avoid adding a "department type" member. After all, that's implicit from the type parameter T. But you could add that easily to the above if you want.
If and when you find that the types do have something in common, such that your Transaction<T> type needs to do more than simply hold onto an instance of one of those types (which is about all it can do without a constraint), then you will be able to put that commonality into an interface or base class (depending on the specific need), and specify that in a constraint for the Transaction<T> class.
Note that it's not clear what you mean for the GenerateOutput() to do, or how it should work. But assuming that you want output that is specific for each Entity value, it seems to me that that is your "something in common". I.e., it's not the Transaction<T> class at all that needs to implement that method, but rather each entity type. In that case, you have something like this:
interface IDepartmentEntity
{
void GenerateOutput();
}
class Office : IDepartmentEntity
{
public void GenerateOutput() { /* department-specific logic here */ }
}
// etc.
Then you can declare:
class Transaction<T> where T : IDepartmentEntity
{
public bool Success { get; private set; }
public T Entity { get; private set; }
public Transaction(bool success, T entity)
{
Success = success;
Entity = entity;
}
public void GenerateOutput() { Entity.GenerateOutput(); }
}
EDIT:
Per Prasant's follow-up edit, with a request for advice on the GetTransactionObject()…
The right way to do this depends on the caller and the context, a detail not provided in the question. IMHO, the best scenario is where the caller is aware of the type. This allows the full power of generics to be used.
For example:
class TransactionFactory
{
public Transaction<T> GetTransactionObject<T>()
where T : IDepartmentEntity, new()
{
return new Transaction<T>()
{
Data = new T(),
params = null
}
}
}
Then you call like this:
Transaction<FireData> transaction = factory.GetTransactionObject<FireData>();
The caller, of course already knowing the type it is creating, then can fill in the appropriate properties of the transaction.Data object.
If that approach is not possible, then you will need for Transaction<T> itself to have a base class, or implement an interface. Note that in my original example, the IDepartmentEntity interface has only one method, and it's the same as the GenerateOutput() method in the Transaction class.
So maybe, that interface is really about generating output instead of being a data entity. Call it, instead of IDepartmentEntity, something like IOutputGenerator.
In that case, you might have something like this:
class Transaction<T> : IOutputGenerator
{
// all as before
}
class TransactionFactory
{
public IOutputGenerator GetTransactionObject(string org)
{
if( typeClassLookup.TryGetValue(org, out typeValue))
{
switch (typeValue.ToString())
{
case "policeData":
transactionObject = new Transaction<PoliceData>() { Data = new PoliceData(), params = null};
case "FireData":
transactionObject = new Transaction<FireData>() {Data = new FireData(), params = null};
}
}
return transactionObject;
}
}
This is an inferior solution, as it means the caller can only directly access the IOutputGenerator functionality. Anything else requires doing some type-checking and special-case code, something that really ought to be avoided whenever possible.
Note: if the Transaction type has other members which, like the GenerateOutput() method, are independent of the contained type T here, and which would be useful to callers who don't know T, then a possible variation of the above is to not reuse the interface used for the department-specific data types, but instead declare a base class for Transaction<T>, named of course Transaction, containing all those members not related to T. Then the return value can be Transaction.
What type does the class in "3." of the Transaction class need to be?
To decouple your department classes from the various export types, I recommend you make the department classes implement a common interface. Something like this:
public interface Exportable {
// return a list of attribute names, values, and types to export
IList<Tuple<String, String, Type>> GetAttributes();
}
For example:
public class Police : Exportable {
public IList<Tuple<String, String, Type>> GetAttributes() {
// return list size 3 - attribute info for Age, VehicleNumber, Supervisor
}
}
Is the overall design appropriate? What other designs should I consider?
The Transaction class design doesn't seem well suited for this problem.
Consider an Export class with a method for each export type, each method which receives the attributes returned from the Exportable interface method. Basic outline:
public static class Export {
public static boolean CSV(IList<Tuple<String, String, Type>> attributes) {
// export attributes to CSV, return whether succeeded
}
public static boolean Excel(IList<Tuple<String, String, Type>> attributes) {
// export attributes to Excel, return whether succeeded
}
// same thing for XML
}
I have an attribute that I am using to decorate object properties with. The attribute identifies the properties as needing validation to be performed on them. I am essentially implementing the Strategy Pattern and building all of the validation (really only about 6 types) in to individual objects that I can use across multiple classes. What I want to do, is provide parameters to the validation classes, without having to create an attribute for each validation object variation.
My attribute looks like this:
[AttributeUsage(AttributeTargets.Property)]
public class ValidationRuleAttribute : Attribute
{
public ValidationRuleAttribute(Type validationRule, string customFailureMessage = "")
{
if (typeof(IValidationRule).IsAssignableFrom(validationRule))
{
this.ValidationRule = string.IsNullOrEmpty(customFailureMessage)
? Activator.CreateInstance(validationRule, customFailureMessage) as IValidationRule
: Activator.CreateInstance(validationRule) as IValidationRule;
}
else
{
throw new ArgumentException(
string.Format(
"ValidationRule attributes can only be used with IValidationRule implementations. The '{0}' Tyoe is not supported.",
validationRule.Name));
}
}
public IValidationRule ValidationRule { get; private set; }
}
As an example, I have a simple StringIsNotNull validation object. I want to expand on it by allowing me to specify a minimum string length requirement. So the StringIsNotEmptyValidation would become StringHasMinimumLengthValidation
public class StringIsNotEmptyValidation : IValidationRule
{
private readonly string customErrorMessage;
public StringIsNotEmptyValidation()
{
}
public StringIsNotEmptyValidation(string customErrorMessage)
{
this.customErrorMessage = customErrorMessage;
}
public string ResultMessage { get; private set; }
public IValidationMessage Validate(System.Reflection.PropertyInfo property, IValidatable sender)
{
string value = property.GetValue(sender).ToString();
// Validate
bool isFailed = string.IsNullOrWhiteSpace(value);
if (isFailed)
{
if (string.IsNullOrEmpty(this.customErrorMessage))
{
DisplayNameAttribute displayName = property.GetCustomAttribute<DisplayNameAttribute>(true);
string errorMessage = displayName == null
? string.Format("You can not leave {0} empty.", property.Name)
: string.Format("You can not leave {0} empty.", displayName.DisplayName);
this.ResultMessage = errorMessage;
return new ValidationErrorMessage(errorMessage);
}
else
{
this.ResultMessage = this.customErrorMessage;
return new ValidationErrorMessage(customErrorMessage);
}
}
this.ResultMessage = string.Empty;
return null;
}
}
Within my model, I decorate my property with the attribute and validation object.
[RepositoryParameter(DbType.String)]
[ValidationRule(typeof(StringIsNotEmptyValidation))]
public string WorkDescription
{
get
{
return this.workDescription ?? string.Empty;
}
set
{
this.SetPropertyByReference(ref this.workDescription, value);
if (this.HasValidationMessageType<ValidationErrorMessage>(this.GetPropertyName(p => p.WorkDescription)))
{
this.Validate();
}
}
}
What I want to do, is write my attribute usage like this:
[ValidationRule(new StringIsNotEmptyValidation(minimumLength: 4))]
Since you can't instance objects in an attribute constructor, I'm forced to provide the attributes in my attribute constructor like this:
[ValidationRule(typeof(StringIsNotEmptyValidation), minLength: 4)]
I don't like this because if I have a ObjectIsNotNull or a StringIsInRange I will need to do two things:
Create a new attribute for each parameter variation (or a lot of overloads)
Set up the validation rule instances within the constructor, which will have varying property names.
The Validation object implements the following interface
public interface IValidationRule
{
string ResultMessage { get; }
IValidationMessage Validate(PropertyInfo property, IValidatable sender);
}
I don't want to bloat my interface with a large number of properties that might be used or might not be used depending on the Rule implementing it. It also makes it difficult to assign attribute params to the rule object.
So my question is how can I provide parameters to the IValidationRule concrete classes, without creating multiple attribute types to facilitate this? This is being used so that I an do cross-object validation. The PropertyInfo passed in to the validation rule is from a cache of PropertyInfo's. I need to keep the amount of reflection used down, otherwise I'd just use attributes for each rule parameter and use reflection on sender to figure out what ranges to use.
Update
After discussing this with Corey, it does indeed appear that attributes are supported in Universal Apps and it is only the DataAnnotations namespace that is missing. In order to get access to the attributes, I had to add a using statement to System.Reflection in order to gain access to a series of extension methods that expose the GetCustomAttribute methods. They are now extension methods and not built in to the Type class.
So I suppose in the end, I can just create my validation logic within the attributes, instead of individual objects. I can't think of any downsides to going this route.
In order to access the attributes in a Universal App, you have to include System.Reflection as a using statement, then access via the GetRuntimeProperties() extension method.
var validationRule = this
.GetType()
.GetRuntimeProperties() // Can be GetRuntimeFields or GetRuntimeMethods as well.
.FirstOrDefault(p => p.GetCustomAttribute<IntegerInRangeAttribute>() != null);
So there are a few options here.
First, and often used, is to have a different attribute for each type of rule you want to process. You are already building classes for each of your rules, so instead of having some encapsulating attribute that instantiates them all just make each rule an attribute:
[StringMinLengthRule(5)]
public string SomeString { get; set; }
Build the validation logic into your attributes - say with a base attribute that does the bulk of the work, calling a virtual method to do the actual validation. Then you can just enumerate the rule attributes and call them from your validation method.
Next, you can have a number of different properties on your attribute that can be set during declaration to provide the properties for your various rules:
[Validation(RuleType.StringMinLength, MinLength = 5)]
public string SomeString { get; set; }
You could still have the rules be processed in the ValidationAttribute itself, or create IValidationRule instances at run-time to process the actual validations. Unfortunately there's nothing to stop you from adding a Validation attribute that sets the wrong properties for the rule type, resulting in errors at run-time when you try to validate an instance.
Finally, something that works but probably shouldn't... and it's kinda ugly:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class ValidationRuleAttribute : Attribute
{
public IValidationRule ValidationRule { get; private set; }
public ValidationRuleAttribute(RuleType type, params object[] parms)
{
if (type == RuleType.NotNull)
{
if (parms.Length != 0)
throw new ArgumentException("RuleType.NotNull requires 0 parameters", "parms");
ValidationRule = new NotNullValidation();
}
if (type == RuleType.StringMinLength)
{
if (parms.Length != 1)
throw new ArgumentException("RuleType.StringMinLength requires 1 parameter", "parms");
if (!(parms[0] is int))
throw new ArgumentException("RuleType.StringMinLength requires an integer", "parms");
ValidationRule = new StringLengthValidation((int)parms[0]);
}
}
}
The biggest problem with it is that it won't complain until you try to instantiate a class at run-time that has a bad Validation attribute. Your code can run quite happily up until the point where it tries to create an instance of that bad class, at which point all of the attributes will actually be constructed and those ArgumentExceptions start flying.
In fact only the first option doesn't suffer from run-time problems, because you can control the types of parameters being supplied by using the correct constructor formats. You can still tell it to do silly things - like requiring that strings must have less than 0 length for instance - but that's up to you :P
I've been working on a project for a while to parse a list of entries from a csv file and use that data to update a database.
For each entry I create a new user instance that I put in a collection. Now I want to iterate that collection and compare the user entry to the user from the database (if it exists). My question is, how can I compare that user (entry) object to the user (db) object, while returning a list with differences?
For example following classes generated from database:
public class User
{
public int ID { get; set; }
public string EmployeeNumber { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Nullable<int> OfficeID { get; set; }
public virtual Office Office { get; set; }
}
public class Office
{
public int ID { get; set; }
public string Code { get; set; }
public virtual ICollection<User> Users { get; set; }
}
To save some queries to the database, I only fill the properties that I can retrieve from the csv file, so the ID's (for example) are not available for the equality check.
Is there any way to compare these objects without defining a rule for each property and returning a list of properties that are modified? I know this question seems similar to some earlier posts. I've read a lot of them but as I'm rather inexperienced at programming, I'd appreciate some advice.
From what I've gathered from what I've read, should I be combining 'comparing properties generically' with 'ignoring properties using data annotations' and 'returning a list of CompareResults'?
There are several approaches that you can solve this:
Approach #1 is to create separate DTO-style classes for the contents of the CSV files. Though this involves creating new classes with a lot of similar fields, it decouples the CSV file format from your database and gives you the ability to change them later without influencing the other part. In order to implement the comparison, you could create a Comparer class. As long as the classes are almost identical, the comparison can get all the properties from the DTO class and implement the comparison dynamically (e.g. by creating and evaluating a Lambda expression that contains a BinaryExpression of type Equal).
Approach #2 avoids the DTOs, but uses attributes to mark the properties that are part of the comparison. You'd need to create a custom attribute that you assign to the properties in question. In the compare, you analyze all the properties of the class and filter out the ones that are marked with the attribute. For the comparison of the properties you can use the same approach as in #1. Downside of this approach is that you couple the comparison logic tightly with the data classes. If you'd need to implement several different comparisons, you'd clutter the data classes with the attributes.
Of course, #1 results in a higher effort than #2. I understand that it is not what you are looking for, but maybe having a separate, strongly-typed compared class is also an approach one can think about.
Some more details on a dynamic comparison algorithm: it is based on reflection to get the properties that need to be compared (depending on the approach you get the properties of the DTO or the relevant ones of the data class). Once you have the properties (in case of DTOs, the properties should have the same name and data type), you can create a LamdaExpression and compile and evaluate it dynamically. The following lines show an excerpt of a code sample:
public static bool AreEqual<TDTO, TDATA>(TDTO dto, TDATA data)
{
foreach(var prop in typeof(TDTO).GetProperties())
{
var dataProp = typeof(TDATA).GetProperty(prop.Name);
if (dataProp == null)
throw new InvalidOperationException(string.Format("Property {0} is missing in data class.", prop.Name));
var compExpr = GetComparisonExpression(prop, dataProp);
var del = compExpr.Compile();
if (!(bool)del.DynamicInvoke(dto, data))
return false;
}
return true;
}
private static LambdaExpression GetComparisonExpression(PropertyInfo dtoProp, PropertyInfo dataProp)
{
var dtoParam = Expression.Parameter(dtoProp.DeclaringType, "dto");
var dataParam = Expression.Parameter(dataProp.DeclaringType, "data");
return Expression.Lambda(
Expression.MakeBinary(ExpressionType.Equal,
Expression.MakeMemberAccess(
dtoParam, dtoProp),
Expression.MakeMemberAccess(
dataParam, dataProp)), dtoParam, dataParam);
}
For the full sample, see this link. Please note that this dynamic approach is just an easy implementation that leaves room for improvement (e.g. there is no check for the data type of the properties). It also does only check for equality and does not collect the properties that are not equal; but that should be easy to transfer.
While the dynamic approach is easy to implement, the risk for runtime errors is bigger than in a strongly-typed approach.
Let's say I have an Entity Object 'Jewels' that has the properties 'Name' and 'Birthdate'.
I want to implement a LINQ query that returns an object that has 'Name', 'Birthdate' and 'Birthstone'. So I extend 'Jewels' like this:
public partial class JewelStones : Jewels
string Birthstone = null;
public void JewelsWithStone()
{
this.Birthstone = "diamond";
//(we figure out what stone applies to the month here)
}
I can get this far, and I THINK I'm on the right track, but I don't know how to write a LINQ query and get back an object that includes Birthstone, so I can bind that object to a grid that will show Birthstone, which I'm not storing anywhere, as it's always calculated (this is pretend data, sorry if it's not logical).
List<Jewel> jewels = new List<Jewel>;
using (jewelentities db = new jewelentities())
{
jewels = (from j in db.Jewels select j).ToList();
}
How do I fill up my JewelStone object with Name, Birthdate, and Birthstone?
If I'm not following best practice here, please let me know!
EDIT
I've tried adding a partial class to the Entity partial class. When I reference the Jewel class now, it 'sees' the Birthstone property, but it is null. I don't know why? Here is the partial class:
public partial class Jewel
{
private string _birthstone;
public string Birthstone
{
get { return _birthstone; }
set
{
JewelBusiness jewelBusiness = new JewelBusiness();
_birthstone = jewelBusiness.RequestBirthstone(birthmonth);
}
}
}
If I use LINQ to query the entity to get a list of Jewel records, I get all the info from the Entity, Jewel.Birthstone is there, but it is null. However if I do a foreach on the results ---
foreach (Jewel j in jewels)
{
string stone = jewelBusiness.RequestBirthstone(j.Birthmonth);
}
stone will equal the expected result (birthstone for that month).
Why doesn't my partial class return the birthstone??
I'm not sure I understand your requirement correctly. But if you don't want to store Birthstone but calculate it on the fly, just change your code to
public partial class Jewel
{
private string _birthstone;
public string Birthstone
{
get
{
if (_birthstone == null)
{
JewelBusiness jewelBusiness = new JewelBusiness();
_birthstone = jewelBusiness.RequestBirthstone(birthmonth);
}
return _birthstone;
}
}
}
Isn't your Jewels EntityObject in a partial class too? You can most likely just add a Jewels partial class to "extend" it and add the wanted property there.
For me, it depends on where the logic for the calculated column resides.
If it resides in database, then you must do join query in the Linq. I assume in this case, you has a table named BirthStoneTable, with the month as the relation. I don't suggest to add a ternary operation inside linq query, such as select j.BirthDate.Month == 1 ? "Diamond" : //etc etc. It is hard to debug and to track (moreover for code coverage reason).
If it resides in UI specific (only to improve the display), I usually add a type-casted class, such as:
public class JewelUI{
public explicit operator JewelUI(Jewel jewel){
JewelUI jewelUI = new JewelUI();
// assign birthdate and name
jewelUI.BirthStone = GetBirthStone(jewel.BirthDate.Month);
}
public string BirthStone{get;set;};
public string GetBirthStone(int month){
if(month == 1) return "Diamond";
//etc etc
}
}
If the calculated column is used in the business logic, usually I handle the calculation in service / business logic. All of it to ensure the good Separation of Concern.
NB: I may misunderstand your requirement though
Let's say I need to display a list of customers, but only want to display the Name and somehow associate the key to the name within a list control.
It would probably be costly to retrieve the entire list of customers and all it's properties. In this scenario, would it be better to create another class with the properties that are required (in this case Id and Name)?
A basic implementation could look like this:
public class Customer {
public int Id { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public int Age { get; set; }
.....
}
public class CustomerListView {
public int Id { get; set; }
public string Name { get; set; }
}
public interface IRepository<T> {
public T Find(int id);
public IEnumerable<T> FindAll();
....
}
public class Repository<T>: IRepository<T> {
....
}
public class CustomerRepository: Repository<Customer> {
public IEnumerable<CustomerListView> FindAllListView();
}
Would this approach be appropriate? What other options would there be?
In order to achieve such goals, I create a simple 'View' class, for example CustomerView, which just contains the properties that are needed to display an overview.
My Repository then has a method which returns a collection of these CustomerView objects.
I mostly use NHibernate in my projects. Nhibernate allows you to use 'projections'.
So, what I do in my repository is this:
(note that the code below is just some pseudo-code; it won't compile).
public IList<CustomerView> GetAllCustomers()
{
ICriteria crit = _session.CreateCriteria (typeof(Customer));
crit.AddProjection ( ... );
crit.SetResultTransformer (new EntityToBeanTransformer(typeof(CustomerView));
return crit.ToList();
}
In fact, it comes down to this: I tell my O/R mapper that it should query Customers, but that it should return entities of type 'CustomerView'.
In the defintion of the projection, I also define which properties of the Customer class map to which properties of the CustomerView class.
Then, the O/R mapper is smart enough to generate a very simple query, which only retrieves those fields that are required to populate the CustomerView class.
For instance, the query that is executed can be as simple as:
SELECT customerid, customername FROM tblCustomer
If you use IQueryable as your return instead of IEnumerable than there is no cost of doing:
CustomerRepository().GetAll().Find(1) because AsQueryable doesn't actually execute until you request data. That means LINQ can optimize it out to a:
SELECT .... FROM .... WHERE ID = 1 instead of
GET EVERYTHING. FIND WHERE THE ID = 1
See this post for an explanation:
Why use AsQueryable() instead of List()?
Using this approach you could create an anonymous class and futher narrow down the data going over the wire to just what you want. That way the query generated by LINQ is optimized to the fullest.
If you have to retrieve the list form a Database then your proposal makes some sense but I would look into a Linq and anonymous type solution.
If the list of Customers already exists in memory then there there are no savings.
You could combine the techniques used by Nissan and Frederik (anonymous types and NHibernate) by using Linq-to-NHibernate.
Item #31 in Bill Wagner's More Effective C# says "limit type scope by using anonymous types", and I agree. BTW, I recommend the whole book.