attribute on virtual property not showing via reflection - c#

I have an EntityFramework model with attributes, which I use to validate the fields.
private person tipProvider;
[Required]
[ForeignKey("TipProviderId")]
public virtual person TipProvider
{
get { return tipProvider; }
set
{
tipProvider = value;
ValidateProperty(MethodBase.GetCurrentMethod().Name.Replace("set_", ""));
raisePropertyChanged(MethodBase.GetCurrentMethod().Name.Replace("set_", ""));
}
}
I get the PropertyInfo and then its validation attributes, which I use to validate the property:
public virtual void ValidateProperty(string property)
{
errors[property].Clear();
var propertyInfo = this.GetType().GetProperty(property);
var propertyValue = propertyInfo.GetValue(this);
var validationAttributes = propertyInfo.GetCustomAttributes(true).OfType<ValidationAttribute>();
foreach (var validationAttribute in validationAttributes)
{
if (!validationAttribute.IsValid(propertyValue))
{
errors[property].Add(validationAttribute.FormatErrorMessage(string.Empty));
}
}
raiseErrorsChanged(property);
}
When the property is virtual, I cannot find the attributes via reflection. If the virtual keyword is removed, the attributes are found.
I'm really confused by this behavior. Why can't attributes be applied on virtual properties?

I do not know exactly what are you trying to do, but from what I know from EntityFramework, the problem is not exactly what you are thinking. You CAN apply attributes to virtual properties, and it is possible to recover them via reflection without any problem, just the way you are doing.
But on EF entities, when you mark a property as virtual, you are defining to the EF that the property is a navigation property (a property used to access foreign key data in a relationship, and retrieve it as child Entities).
Then, when you get a new instance of this entity from the database context at runtime, and access that property, EF will create a new class (dynamic proxy) derived from your class and uses it instead of your original class. Entity Framework does it to maintain the concept of "Lazy Loading" your relationships - avoiding loading an entire new dependent entity tree without being needed.
Because EF makes a new class derived from your Entity, AND the property is being overriden by that, your attribute is not being inherited by it.
You can see more about virtual marks and Navigation properties on this post.

Related

AutoMapper with a complex EF Entity

I have a basic table with a few FK references. So when I retrieve an entity for an update operation; that entity contains ICollectionsof related entites. I also have a main ViewModel inside which each entity is a sub viewModel. My aim is to use Automapper like:
mapper.Map(MainViewmodel obj,MainEntity obj);
For this I have a MappingConfiguration like:
CreateMap<MainViewModel, MainEntity>();
CreateMap<subViewModel1, subEntity1>();
CreateMap<subViewModel2, subEntity2>();
This gives me an Unmapped properties exception because the ICollections are not getting mapped. Could anyone please guide me on the best way to deal with this kind of situation?
thanks.
If I understand you correctly, you has classes like this:
class MainViewModel
{
ICollection<SubViewModel1> SubViewModels { get;set; }
}
class SubViewModel1
{
}
and
class MainEntity
{
ICollection<SubEntity1> SubEntities { get;set; }
}
class SubEntity1
{
}
Then you should create rules for each class, and collection of such classes automaper map automatically.
CreateMap<MainViewModel, MainEntity>();
CreateMap<SubViewModel1, SubEntity1>();
Addditions 1:
Try this method: var mappedMainEntity = rmapper.Map<MainEntity>(MainViewmodel obj);
If you map MainEntity to MainViewModel you need add .ReverseMap() to map rule, like this:
CreateMap().ReverseMap();
CreateMap().ReverseMap();
Additions 2:
AutoMapper mapping public Properties only
If the mapping Properties have different names, you need to use explicitly indicating how to map these Properties. Using ForMember method and MapFrom option. Example

Entity Framework, Generic loading of related entities with a where condition

I'm trying to create a function that generically loads the related child entities with a filter.
All my entities are derived from my own Base Class "BusinessObject"
public abstract class BusinessObject : BaseObject, IBaseObject, ILocalObject
{
[Browsable(false)]
[Key]
public int ID { get; set; }
[Browsable(false)]
public int? HqID { get; set; }
private bool _deleted;
[Browsable(false)]
public bool Deleted
{
get { return _deleted; }
set { CheckPropertyChanged(ref _deleted, value); }
}
}
I have created the following function that when supplied an entity will load all the related child objects.
When defining my entities, all child collections are flagged by my own attribute "EntityChildCollectionAttribute" so I can easily find the collections I want to load.
public virtual void OnLoadEntityChildren(object entity)
{
var propNames = entity.GetPropertyNames();
foreach (var propName in propNames.Where(propName => entity.PropertyHasCustomAttribute(propName, typeof(EntityChildCollectionAttribute))))
{
MyData.Entry(entity).Collection(propName).Load();
}
}
This works lovely!
My Problem comes when I want to filter the child collection.
In this case I want to only load child entities where Deleted == false.
I cannot work out how to do this!
I have had many attempts and replacing MyData.Entry(entity).Collection(propName).Load(); with
MyData.Entry(entity).Collection(propName).Query().Cast<BusinessObject>().Where(x=>x.Deleted.Equals(false)).Load();
compiles but then I get the error;
"Unable to cast the type 'FmOrderProcessing.Entities.OpDocumentDetail' to type 'FwBaseEntityFramework.BusinessObject'. LINQ to Entities only supports casting EDM primitive or enumeration types."
Any Help/Pointers/Answers will be gratefully received
Thanks in advance
Lance
I was implementing a "Soft Delete" pattern which means the records in the database are flagged as deleted rather than removed (for audit and replication purposes).
All entities are derived from a base definition with a bool Deleted property.
I found the answer here:
https://www.nuget.org/packages/EntityFramework.DynamicFilters
This package allows the definition of global filters in the data context.
I fixed my issue with one line of code in the OnModelCreating override.
modelBuilder.Filter("Deleted", (IBaseObject d) =>d.Deleted, false);
The filter function is applied globally to any entity presenting (in my case) the IBaseObject interface.
I hope this helps any body else with a similar issue

Domain model vs Entity FW: Is this a case when splitting in a persistence model is usefull?

In a DDD approach, I have a Domain Model (DM), with a rich behaviour. Suppose I have a root entity, called Order and relative LineOrder. The exposed collection of LineOrder need to be a IReadOnlyCollection since none can alter the collection arbitrarily. In code:
public class Order : AggregateRoot {
// fields
private List<LineOrder> lineOrder;
// ctors
private Order() {
this.lineOrder = new List<LineOrder>();
// other initializations
}
// properties
public IReadOnlyCollection<LineOrder> LineOrder {
get
{
return lineOrder.AsReadOnly();
}
}
// behaviours
}
So far, so good. But when I want to persist this domain I have some technology restrictions imposed by Entity Framework (a key is needed even if I have a value object, a parameterless constructor and so on) that is not a perfect match with a DDD approach.
Another limitation that I have is:
public class OrderConfiguration : EntityTypeConfiguration<Order>
{
public OrderConfiguration()
{
ToTable("Order");
HasMany<LineOrder>(m => m.LineOrder); // Exception: Cannot convert from IReadOnlyCollection to ICollection
}
}
I cannot cast IReadOnlyCollection to ICollection (incidentally, if LineOrder was an ICollection everything was OK!).
For the reasons I have expressed above: could be usefull in this case create a Persistence Model (with belonging cons: mapping DM/PM and viceversa)?
Are there an alternative? And, above all: are there an alternative that well fit a DDD approach?
Have you tried declaring the LineOrder collection as protected? This way EF has access but consumers do not.
// properties
protected ICollection<LineOrder> LineOrder { get; set; }
You can then expose this collection in a read-only manner to the end user with:
public IReadOnlyCollection<LineOrder> ReadOnlyLineOrder
{
get
{
return LineOrder.ToList().AsReadOnly();
}
}

The property has not been declared on the Type XXX Exception in Entity Framework

I have a file Unit.cs
public class Unit
{
public UnitType UnitTypeState {get;set;}
}
public enum UnitType
{
Folder = 0,
Teststeps = 1,
}
When I put the enum definition into another class like UnitDTO I got this exception:
The property 'UnitTypeState' is not a declared property on type 'Unit'. Verify that the property has not been explicitly excluded from the model by using the Ignore method or NotMappedAttribute data annotation. Make sure that it is a valid primitive property.
Well thats not truee hehe the property UnitTypeState is a declared property in the Unit class class.
How can I fix that without moving the enum back to the Unit class?
UPDATE
I have still done some research about the bug:
"The context cannot be used while the model is being created."
The odd thing is I get this exception on a entity which is the parent of the entity with the UnitTyeState property ?!
using (var context = new ITMS.DataAccess.ITMSContext())
{
return context.Templates.ToList();
}
so it seems the template entity is created then this exception is thrown? Or behaves EF like this: At the first DB access at all every entities or the whole model is created?
Nested types are currently not supported by EF - applies to both StructuralType (i.e. entity and complex types) and enum types.
Adding a link to the EF work item that is exactly about this issue: http://entityframework.codeplex.com/workitem/119
Try using the following, Perhaps the enum just needs to derive from a primitive to work?
public enum UnitType : int
{
Folder = 0,
Teststeps = 1
}

EF4.1 POCO: Why should I use ICollection

In nearly all examples of POCO classes created for Entity Framework 4.1 collections are defined using the ICollection interface:
public class TravelTicket
{
public virtual int Id { get; set; }
public string Destination { get; set; }
public virtual ICollection<Person> Members { get; set; }
}
However, this causes an issue in my code where I need to access a member of the collection by index, e.g.:
Person Paul = TravelTicket.Members[3];
Cannot apply indexing with [] to an expression of type 'System.Collections.Generic.ICollection
So how do I get round this problem and should I always use ICollection for my POCO collections?
It is because once you mark your navigation property virtual the proxy of your entity is created and it uses HashSet for navigation properties - hash set doesn't allow indexing. Accessing related entities by index doesn't seem like good approach because retrieving entity from database doesn't ensure that related entities will always have the same index in the collection.
Just use ToList():
Person Paul = TravelTicket.Members.ToList()[3];
EF isn't going to query data until you actually try to access it - and a collection doesn't try until you iterate it, while ToList must instantiate each instance.
Even better, be more specific:
Person Paul = TravelTicket.Members.Where(m=>m.Id == 3); // or some such similar filter
Then you only instance ONE Member - the one you want.
Note you may need Members.AsQueryable().Where instead - I never remember...
ICollection implements IEnumerable, you should be able to get the item by index using Enumerable.ElementAt<TSource> method

Categories