e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
151 lines
6.0 KiB
C#
151 lines
6.0 KiB
C#
using System.Data.Metadata.Edm;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Globalization;
|
|
using System.Reflection;
|
|
|
|
namespace System.Web.DynamicData.ModelProviders {
|
|
internal sealed class EFColumnProvider : ColumnProvider {
|
|
private EFTableProvider _table;
|
|
private EFAssociationProvider _association;
|
|
private bool _isAssociation;
|
|
private bool _isSortableProcessed;
|
|
private const string StoreGeneratedMetadata = "http://schemas.microsoft.com/ado/2009/02/edm/annotation:StoreGeneratedPattern";
|
|
|
|
public EFColumnProvider(EntityType entityType, EFTableProvider table, EdmMember m, bool isPrimaryKey)
|
|
: base(table) {
|
|
EdmMember = m;
|
|
IsPrimaryKey = isPrimaryKey;
|
|
_table = table;
|
|
MaxLength = 0;
|
|
Name = EdmMember.Name;
|
|
//
|
|
IsCustomProperty = false;
|
|
|
|
//
|
|
var property = EdmMember as EdmProperty;
|
|
|
|
if (property != null) {
|
|
IsForeignKeyComponent = DetermineIsForeignKeyComponent(property);
|
|
IsGenerated = IsServerGenerated(property);
|
|
}
|
|
|
|
ProcessFacets();
|
|
|
|
var navProp = m as NavigationProperty;
|
|
if (navProp != null) {
|
|
_isAssociation = true;
|
|
long key = EFAssociationProvider.BuildRelationshipKey(entityType, navProp.FromEndMember);
|
|
((EFDataModelProvider)table.DataModel).RelationshipEndLookup[key] = this;
|
|
}
|
|
}
|
|
|
|
private bool DetermineIsForeignKeyComponent(EdmProperty property) {
|
|
var navigationProperties = property.DeclaringType.Members.OfType<NavigationProperty>();
|
|
|
|
// Look at all NavigationProperties (i.e. strongly-type relationship columns) of the table this column belong to and
|
|
// see if there is a foreign key that matches this property
|
|
// If this is a 1 to 0..1 relationship and we are processing the more primary side. i.e in the Student in Student-StudentDetail
|
|
// and this is the primary key we don't want to check the relationship type since if there are no constraints we will treat the primary key as a foreign key.
|
|
return navigationProperties.Any(n => EFAssociationProvider.GetDependentPropertyNames(n, !IsPrimaryKey /* checkRelationshipType */).Contains(property.Name));
|
|
}
|
|
|
|
private static bool IsServerGenerated(EdmProperty property) {
|
|
MetadataProperty generated;
|
|
if (property.MetadataProperties.TryGetValue(StoreGeneratedMetadata, false, out generated)) {
|
|
return "Identity" == (string)generated.Value || "Computed" == (string)generated.Value;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void ProcessFacets() {
|
|
foreach (Facet facet in EdmMember.TypeUsage.Facets) {
|
|
switch (facet.Name) {
|
|
case "MaxLength":
|
|
if (facet.IsUnbounded) {
|
|
// If it's marked as unbounded, treat it as max int
|
|
MaxLength = Int32.MaxValue;
|
|
}
|
|
else if (facet.Value != null && facet.Value is int) {
|
|
MaxLength = (int)facet.Value;
|
|
}
|
|
break;
|
|
case "Nullable":
|
|
Nullable = (bool)facet.Value;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal EdmMember EdmMember {
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
#region IEntityMember Members
|
|
|
|
public override PropertyInfo EntityTypeProperty {
|
|
//
|
|
get { return _table.EntityType.GetProperty(Name); }
|
|
}
|
|
|
|
public override Type ColumnType {
|
|
get {
|
|
if (base.ColumnType == null) {
|
|
//
|
|
|
|
|
|
var edmType = EdmMember.TypeUsage.EdmType;
|
|
if (edmType is EntityType) {
|
|
base.ColumnType = ((EFDataModelProvider)this.Table.DataModel).GetClrType(edmType);
|
|
}
|
|
else if (edmType is CollectionType) {
|
|
// get the EdmType that this CollectionType is wrapping
|
|
base.ColumnType = ((EFDataModelProvider)this.Table.DataModel).GetClrType(((CollectionType)edmType).TypeUsage.EdmType);
|
|
}
|
|
else if (edmType is PrimitiveType) {
|
|
base.ColumnType = ((PrimitiveType)edmType).ClrEquivalentType;
|
|
}
|
|
else if (edmType is EnumType) {
|
|
base.ColumnType = ((EFDataModelProvider)this.Table.DataModel).GetClrType((EnumType)edmType);
|
|
}
|
|
else {
|
|
Debug.Assert(false, String.Format(CultureInfo.CurrentCulture, "Unknown EdmType {0}.", edmType.GetType().FullName));
|
|
}
|
|
}
|
|
return base.ColumnType;
|
|
}
|
|
}
|
|
|
|
public override bool IsSortable {
|
|
get {
|
|
if (!_isSortableProcessed) {
|
|
base.IsSortable = (ColumnType != typeof(byte[]));
|
|
_isSortableProcessed = true;
|
|
}
|
|
return base.IsSortable;
|
|
}
|
|
}
|
|
|
|
public override AssociationProvider Association {
|
|
get {
|
|
if (!_isAssociation) {
|
|
return null;
|
|
}
|
|
|
|
if (_association == null) {
|
|
_association = new EFAssociationProvider(this, (NavigationProperty)EdmMember);
|
|
}
|
|
return _association;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
internal static bool IsSupportedEdmMemberType(EdmMember member) {
|
|
var edmType = member.TypeUsage.EdmType;
|
|
return edmType is EntityType || edmType is CollectionType || edmType is PrimitiveType || edmType is EnumType;
|
|
}
|
|
}
|
|
}
|