I have a POCO object in my solution that has some Entity objects as properties. I have done this in many other classes, but not when the base class is a POCO as opposed to another Entity.
Here is the server side version of the class:
public partial class ItemLocationPricingDetail
{
public ItemLocationPricingDetail()
{
}
[Key]
[DataMember]
public int ItemLocationDetailId
{
get;
set; //get { return _itemLocationDetail.Id; }
}
[DataMember]
public int ItemMasterId
{
get
{
if (ItemLocationDetail == null) return 0;
return ItemLocationDetail.ItemMaster.ItemMasterId;
}
}
private EntityRef<ItemLocationDetail> _itemLocationDetail;
[DataMember]
//[Include()]
//[Association("ParentChild", "ItemLocationDetailId", "Id", IsForeignKey = false)]
public ItemLocationDetail ItemLocationDetail
{
get { return _itemLocationDetail.Entity; }
set { _itemLocationDetail.Entity = value; }
}
[DataMember]
public ItemMaster ItemMaster
{
get
{
if (ItemLocationDetail == null) return null;
return ItemLocationDetail.ItemMaster;
}
set { ItemLocationDetail.ItemMaster = value; }
}
private decimal _newPrice;
[DataMember]
public decimal NewPrice
{
get { return _newPrice; }
set { _newPrice = value; }
}
}
I do have a client side partial class, but that doesn't deal with any of these properties.
I also have a meta data class as follows:
[MetadataTypeAttribute(typeof(ItemLocationPricingDetail.ItemLocationPricingDetailMetadata))]
public partial class ItemLocationPricingDetail
{
internal sealed class ItemLocationPricingDetailMetadata
{
[Key]
public int ItemLocationDetailId { get; set; }
[Include]
[Association("ItemLocationDetailAssociation", "ItemLocationDetailId", "Id")]
public EntityRef<ItemLocationDetail> ItemLocationDetail { get; set; }
[Include]
[Association("ItemMasterAssociation", "ItemMasterId", "ItemMasterId")]
public EntityRef<ItemMaster> ItemMaster { get; set; }
}
}
The issue is that I make a simple modification to a property of the ItemLocationDetail property. I then call SubmitChanges on the DataContext which works perfectly fine. The issue is that after that has completed, something, tries to access some of the properties in the ItemLocationPricingDetail class, but for some reason the ItemLocationDetail is now null. This is why there are null checks on that property throughout the class, just so I can try and see where the issue is, but I can't find the problem.
I am guessing it occurs when the ItemLocationPricingDetail class is being updated after the SubmitChanges has been called, but I'm unsure of the working of RIA services at that level.
As you can can see there is some commented out code around the ItemLocationDetail property, while this compiles and no errors are given, the issue still persists. That is the only information vaguely related to this issue I have found on the internet.
Could anyone make any suggestions? If you need more information I will provide it.
Thanks.
Related
I'm writing a RESTful API, in which the entities are persisted in Azure Storage Table service.
One of my entities is Tenant entity and it would look like this:
public class TenantEntity : BaseEntity
{
public string Name
{
get => PartitionKey;
set
{
PartitionKey = value;
RowKey = value;
}
}
[JsonIgnore]
public string DefaultActionSerialized
{
get => JsonConvert.SerializeObject(DefaultAction);
set => DefaultAction = JsonConvert.DeserializeObject<ScheduledAction>(value);
}
[IgnoreProperty]
public ScheduledAction DefaultAction { get; set; }
}
[JsonConverter(typeof(ScheduledActionJsonConverter))]
public abstract class ScheduledAction
{
public abstract ScheduledActionType ActionType { get; }
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
}
[JsonConverter(typeof(StringEnumConverter))]
public enum ScheduledActionType
{
StorageQueueMessage,
Webhook
}
Please note the DefaultAction property which is of type ScheduledAction.
My original thought was that there will be several ScheduledActions supported, like putting a message in queue, or calling a webhook etc.
However, I'm not sure how would the DTO of the Tenant entity would look like.
Shall I replicate and create a DTO for the abstract ScheduledAction class, and then do the same for each of its inheritors?
If you would model it differently, then I'd be happy to hear about this as well - but please for the sake of experiencing DTOs, I'd be happy to have an answer for this question as well :)
Right now, the TenantDto class looks like this:
public class TenantDto
{
[Required]
[FromRoute(Name = "tenant")]
[JsonProperty("TenantName")]
[RegularExpression("^[a-z][a-z0-9]+$")]
[StringLength(maximumLength: 24, MinimumLength = 3)]
public string TenantName { get; set; }
[Required]
[JsonProperty("ScheduledAction")]
public ScheduledAction ScheduledAction { get; set; }
public static implicit operator TenantEntity(TenantDto tenantDto)
{
return new TenantEntity
{
Name = tenantDto.TenantName,
DefaultAction = tenantDto.ScheduledAction,
};
}
}
It references the domain model ScheduledAction which I know is bad practice, but could not find a solution which makes more sense to me.
Thank you for helping!
I'm trying to build a series of attribute classes to make it easier for our development team to validate objects. The objects are POCO classes like this.
public class User
{
public string Name { get; set; }
public string Company { get; set; }
}
I want to decorate this model with a custom attribute.
public class User
{
[MustHaveValue]
public string Name { get; set; }
public string Company { get; set; }
}
Then I would create my own class implementing ValidationAttribute, the base class in .NET Framework, which belongs to System.ComponentModel.DataAnnotations.
public class MustHaveValueAttribute : ValidationAttribute
{
.
.
public override IsValid(object value)
{
// validation logic.
}
}
And then I can validate the User model whenever I want by making the set of instances like ValidationContext, List<ValidationResult>.
But in an enterprise environment, problems just can't be solved by a specific class. My validation scenario requires more complex and more flexible ways. Imagine that one of the required validation scenarios would something like this.
public class User
{
public string Name { get; set; }
public string Company { get; set; }
// Check if an item exists in this list.
[MustHaveMoreThanOneItem]
public IList<Client> Clients { get; set; }
}
Then I would need to make another attribute class
public class MustHaveMoreThanOneItemAttribute : ValidationAttribute
{
.
.
public override IsValid(object value)
{
// Let's assume this value is List<Client> for now.
// I know the exact type, so I'm going to cast it to List<Client> without further considerations
List<Client> clients = value as List<Client>;
if(clients.Count > 0) {
return true;
} else {
return false;
}
}
}
But the problem is that there are a lot of other models that have a nested list items. Try to imagine the time when I want to reuse the MustHaveMoreThanOneItem in one of the other models like...
public class Department
{
public string Name { get; set; }
[MustHaveMoreThanOneItem]
public IList<Employee> { get; set; }
}
You already know that it's not going to work because it was strongly typed only for List<Client>. So I decided to use Generic there to solve this problem.
But to my disappointment, the _Attribute interface doesn't support Generic. There's no additional implementation like _Attribute<T> : Attribute and therefore, no ValidationAttribute<T> alas!! I just cannot use Generic here !!
public class Department
{
public string Name { get; set; }
// No way to use this syntax.
[MustHaveMoreThanOneItem<Employee>]
public IList<Employee> { get; set; }
}
So I made a conclusion that Attribute must have been designed for a fixed set of validations like email format, card format, null check, and etc IMAO.
But I still want to use an attribute and give a lot of flexibilities in it to prevent the duplicated, verbose validation codes like this.
if(model.Clients.Count > 0) ...
if(model.Name != null) ...
if(model.Clients.GroupBy(x => x.Country == Country.USA).Count >= 1) ...
if(model.Clients.Where(x => x.CompanyName == Company.Google).ToList().Count > 1 ) ...
.
.
.
I want to pose two questions here.
If Attirbute supports Generic, this problem will be solved?
Is there any way to implement Generic Attribute? in order to use
[MustHaveMoreThanOneItem<Employee>] annotation on a class member?
You can generically check any object that implements IEnumerable like this:
public class MustHaveMoreThanOneItemAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
// omitted null checking
var enumerable = value as IEnumerable;
var enumerator = enumerable.GetEnumerator();
if (!enumerator.MoveNext())
{
return false;
}
if (!enumerator.MoveNext())
{
return false;
}
return true;
}
}
C# by definition does not support generic type attributes, although this has been requested actively for a long time:
https://github.com/dotnet/roslyn/issues/953
https://github.com/dotnet/csharplang/issues/124
However, you can still inject a type into a validation attribute via constructor. You then can use reflection or whatever you need to define your custom validation criteria.
public class MustHaveMoreThanOneItemAttribute : ValidationAttribute
{
public Type EnumerableType { get; }
public MustHaveMoreThanOneItemAttribute(Type t)
=> this.EnumerableType = typeof(ICollection<>).MakeGenericType(t);
public override bool IsValid(object value)
{
var count = this.EnumerableType.GetProperty("Count").GetValue(value) as int?;
return (count ?? 0) > 1;
}
}
Now this allows you to use something similar to your goal:
public class Department
{
public string Name { get; set; }
[MustHaveMoreThanOneItem(typeof(Employee))]
public IList<Employee> { get; set; }
}
i am having around 7 models who have same properties(atributes). On view page i am using a model(name = commonModel) which contains all those properties and a extra property to choose in which model's database i want to save that sent data so i created a valuesRelocate Method that will assign all the properties of commonModel to the choosen model (in this case article).
The code i gave below is working but i am getting a error when assigning value of a property of commonModel to a property of article.
What is the better way to do this.
Error is at tempModel.question
public ActionResult Create([Bind(Include =
"Id,question,ans,ruleApplicable,hint,exception,modelSelector")]
commonModel commonModel)
{
if (ModelState.IsValid)
{
if (commonModel.modelSelector == "article")
{
article model2 = new article();
article model1 = valuesRelocate<article>(commonModel,
model2);
db.articleDb.Add(model1);
db.SaveChanges();
return RedirectToAction("Index");
}
}
return View(commonModel);
}
private T valuesRelocate<T>(commonModel commonModel, T tempModel) {
tempModel.question = commonModel.question;
return tempModel;
}
I am using a abstract base class named baseGrammar .code for both the class is shown below
public abstract class baseGrammar
{
[Key]
public int Id { get; set; }
[Required]
public string question { get; set; }
[Required]
public string ans { get; set; }
public string ruleApplicable { get; set; }
public string hint { get; set; }
public bool exception { get; set; }
}
the one shown above is base class
and those shown below are derived classes
i use different classes because i wanted to have different classes for different grammatical concepts.
public class article : baseGrammar
{
}
public class commonModel : baseGrammar
{
[Required]
public string modelSelector { get; set; }
}
hope this helps.
You just need to constrain the type parameter T to be derived from your base class:
// Names changed to follow .NET naming conventions
private T RelocateValues<T>(BaseGrammar baseModel, T tempModel)
where T : BaseGrammar
{
tempModel.question = baseModel.question;
return tempModel;
}
However, given that you're modifying the incoming model, you could remove the return value and just change the method to:
private void RelocateValues(BaseGrammar from, BaseGrammar to)
{
to.question = from.question;
}
Then in your calling code:
Article model = new Article();
RelocateValues(model);
db.ArticleDb.Add(model);
There's no need to have two separate variables which will refer to the same object anyway...
My situation is the following:
I'm coding a MVC website on Visual Studio 2013 using database-first approach with Entity Framework.
EF automatically generates the models. But I need to add custom attributes (~NOT~ necessarily for data validation but also for internal processes) and, via reflection, access those custom attributes.
Let's say I have
public partial class Application {
public int AppID {get; set;}
public string Name {get; set;}
//etc...
}
I've tried the following approaches:
• On a different file I continue the partial class:
public partial class Application {
[MyAttributeOne]
public int AppID { get; set; }
[DataType(DataType.Text)]
[MyAttributeTwo]
public string Name { get; set; }
}
• Use the MetaData class
public class ApplicationMetadata {
[MyAttributeOne]
public int SolutionID { get; set; }
[DataType(DataType.Text)]
[MyAttributeTwo]
public string Name { get; set; }
}
[MetadataType(typeof(ApplicationMetadata))]
public partial class Application { }
• Inherit the class with attributes:
public class ApplicationMetadata {
[MyAttributeOne]
public int SolutionID { get; set; }
[DataType(DataType.Text)]
[MyAttributeTwo]
public string Name { get; set; }
}
public partial class Application : ApplicationMetadata { }
• And the 'Buddy class' approach where I do basically the previous 2 approaches but instead I define the class with the attributes inside the 'Application' class.
Am I doing something wrong? Or is this simply impossible?
I need to be able to make the following code work:
foreach (PropertyInfo propertyInfo in currentObject.GetType().GetProperties())
{
foreach (CustomAttributeData attrData in propertyInfo.GetCustomAttributesData())
{
if (typeof(attrData) == typeof(MyAttributeOne))
//stuff
else if (typeof(attrData) == typeof(MyAttributeTwo))
//different stuff
else
//yet more stuff
}
}
Thank you very much for the attention!
Regards.
OK, this is a little involved but it's fairly simple. This is also really a bit of a brain dump but it does work and gives you enough to work with. Lets set up with some basics:
//A couple of custom attributes
public class MyAttributeOne : Attribute { }
public class MyAttributeTwo : Attribute { }
//A metadata class where we can use the custom attributes
public sealed class MyEntityMetadata
{
//This property has the same name as the class it is referring to
[MyAttributeOne]
public int SomeProperty { get; set; }
}
//And an entity class where we use System.ComponentModel.DataAnnotations.MetadataType
//to tell our function where the metadata is stored
[MetadataType(typeof(MyEntityMetadata))]
public class MyEntity
{
public int SomeProperty { get; set; }
}
OK, still with me? Now we need a function to process the properties in the same way you did earlier:
public void DoStuff(object currentObject)
{
//Lets see if our entity class has associated metadata
var metaDataAttribute = currentObject.GetType()
.GetCustomAttributes()
.SingleOrDefault(a => a is MetadataTypeAttribute) as MetadataTypeAttribute;
PropertyInfo[] metaProperties = null;
//Cache the metadata properties here
if (metaDataAttribute != null)
{
metaProperties = metaDataAttribute.MetadataClassType.GetProperties();
}
//As before loop through each property...
foreach (PropertyInfo propertyInfo in currentObject.GetType().GetProperties())
{
//Refactored this out as it's called again later
ProcessAttributes(propertyInfo.GetCustomAttributes());
//Now check the metadata class
if (metaProperties != null)
{
//Look for a matching property in the metadata class
var metaPropertyInfo = metaProperties
.SingleOrDefault(p => p.Name == propertyInfo.Name);
if (metaPropertyInfo != null)
{
ProcessAttributes(metaPropertyInfo.GetCustomAttributes());
}
}
}
}
And of course, here is the refactored method to process the attributes:
private void ProcessAttributes(IEnumerable<Attribute> attributes)
{
foreach (var attr in attributes)
{
if (attr is MyAttributeOne)
{
Console.WriteLine("MyAttributeOne found");
}
else if (attr is MyAttributeTwo)
{
Console.WriteLine("MyAttributeTwo found");
}
else
{
}
}
}
Let's say I have a class from a 3rd-party, which is a data-model. It has perhaps 100 properties (some with public setters and getters, others with public getters but private setters). Let's call this class ContosoEmployeeModel
I want to facade this class with an interface (INavigationItem, which has Name and DBID properties) to allow it to be used in my application (it's a PowerShell provider, but that's not important right now). However, it also needs to be usable as a ContosoEmployeeModel.
My initial implementation looked like this:
public class ContosoEmployeeModel
{
// Note this class is not under my control. I'm supplied
// an instance of it that I have to work with.
public DateTime EmployeeDateOfBirth { get; set; }
// and 99 other properties.
}
public class FacadedEmployeeModel : ContosoEmployeeModel, INavigationItem
{
private ContosoEmployeeModel model;
public FacadedEmployeeModel(ContosoEmployeeModel model)
{
this.model = model;
}
// INavigationItem properties
string INavigationItem.Name { get; set;}
int INavigationItem.DBID { get; set;}
// ContosoEmployeeModel properties
public DateTime EmployeeDateOfBirth
{
get { return this.model.EmployeeDateOfBirth; }
set { this.model.EmployeeDateOfBirth = value; }
}
// And now write 99 more properties that look like this :-(
}
However, it's clear that this will involve writing a huge amount of boilerplate code to expose all the properties , and I'd rather avoid this if I can. I can T4 code-generate this code in a partial class, and will do if there aren't any better ideas, but I though I'd ask here to see if anyone had any better ideas using some super wizzy bit of C# magic
Please note - the API I use to obtain the ContosoEmployeeModel can only return a ContosoEmployeeModel - I can't extend it to return a FacededEmployeeModel, so wrapping the model is the only solution I can think of - I'm happy to be corrected though :)
The other approach may be suitable for you is to use AutoMapper to map base class to your facade here is sample code:
class Program
{
static void Main(string[] args)
{
var model = new Model { Count = 123, Date = DateTime.Now, Name = "Some name" };
Mapper.CreateMap<Model, FacadeForModel>();
var mappedObject = AutoMapper.Mapper.Map<FacadeForModel>(model);
Console.WriteLine(mappedObject);
Console.ReadLine();
}
class Model
{
public string Name { get; set; }
public DateTime Date { get; set; }
public int Count { get; set; }
}
interface INavigationItem
{
int Id { get; set; }
string OtherProp { get; set; }
}
class FacadeForModel : Model, INavigationItem
{
public int Id { get; set; }
public string OtherProp { get; set; }
}
}
Resharper allows the creation of "delegating members", which copies the interface of a contained object onto the containing object and tunnels the method calls/property access through to the contained object.
http://www.jetbrains.com/resharper/webhelp/Code_Generation__Delegating_Members.html
Once you've done that, you can then extract an interface on your proxy class.