justlogin justlogin - 1 month ago 10
C# Question

How get types of entities on ends of association sets in Entity Framework?

I develop method, which resets cache, when Entity Framework is saving changes. I handle this event in

objectContext_SavingChanges


private void objectContext_SavingChanges(object sender, EventArgs e)
{
if (_cacheProvider != null)
{
var objectContext = (this as IObjectContextAdapter).ObjectContext;
var entries =
objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Modified | EntityState.Added);
var result = new List<string>();

if (entries != null && entries.Any())
{
foreach (var entry in entries.Where(entry => !entry.IsRelationship))
{
var entity = entries.Select(r => r.Entity).FirstOrDefault();
if (entity != null)
{
var genericTypeName =
typeof(List<>).MakeGenericType(ObjectContext.GetObjectType(entity.GetType()))?.ToString();
_cacheProvider.ResetCache(genericTypeName);
}
}

foreach (var entry in entries.Where(entry => entry.IsRelationship))
{
var set = entry.EntitySet as AssociationSet;
if(set !=null)
{
var firstEntitySet = set.AssociationSetEnds[0].EntitySet;
var secondEntitySet = set.AssociationSetEnds[1].EntitySet;

var firstEntitySetName = firstEntitySet.ElementType.FullName + "," + Assembly.GetExecutingAssembly().FullName;
var secondEntitySetName = secondEntitySet.ElementType.FullName + "," + Assembly.GetExecutingAssembly().FullName;

var firstGenericTypeName =
typeof(List<>).MakeGenericType((Type.GetType(firstEntitySetName)))?.ToString();

var secondGenericTypeName =
typeof(List<>).MakeGenericType((Type.GetType(secondEntitySetName)))?.ToString();

_cacheProvider.ResetCache(firstGenericTypeName);
_cacheProvider.ResetCache(secondGenericTypeName);
}
}
}
}
}


It works great for entity's entries of object state entries, but does not work for association sets. I need to reset cache for both entities on other sides of relation. AssociationSet has "FullName" property but this property does not contain real name of type. It contains short name of type and assembly name, but not contains full namespace in solution.

For example, type has real full name in solution
DataAccess.Entities.CachedEntity
, namespace:
DataAccess.Entities
, short name:
CachedEntity
. But full name in association set will be
DataAccess.CachedEntity
.

Can I get full name of type for each end of relation?

Answer

I decided this task so:

        var clrTypeNamespace = @"http://schemas.microsoft.com/ado/2013/11/edm/customannotation:ClrType";

        var firstEdmType = set.AssociationSetEnds[0]?.EntitySet?.ElementType;
        var secondEdmType = set.AssociationSetEnds[1]?.EntitySet?.ElementType;

        var firstType = firstEdmType?.MetadataProperties.SingleOrDefault(p => p.Name == clrTypeNamespace)?.Value as Type;
        var secondType = secondEdmType?.MetadataProperties.SingleOrDefault(p => p.Name == clrTypeNamespace)?.Value as Type; 

We can use namespace clrTypeNamespace of CLR type in EDM and find real type of entity in MetadataProperties

Also, we can use navigation properies for each relationship's set. But this solution is sutable for situations, when navigation properties exist on both sides of relationship.

        var asem = set.AssociationSetEnds[0].CorrespondingAssociationEndMember;
        var propInfo = asem.MetadataProperties.SingleOrDefault(p => p.Name == "ClrPropertyInfo")?.Value as PropertyInfo;