With EF v1, we have an ObjectContext which has one property per EntitySet. The "problem" is that if you have an entity type Person and an entity type Employee which inherits Person, you will have only one property Persons because there is only one EntitySet Persons.
Note that your ObjectContext generated class is partial.
public class SampleEdmxCodeGenerator : BaseCodeGeneratorWithSite
{
private EntityContainer _objectContext;
private Dictionary<string, EntitySetBase> _entitySetNames;
private Dictionary<string, List<EntityType>> _typesHierarchyToAddInObjectContext;
private bool _first = true;
public Dictionary<string, EntitySetBase> EntitySetNames
{
get
{
if (_entitySetNames == null)
_entitySetNames = new Dictionary<string, EntitySetBase>();
return _entitySetNames;
}
}
private Dictionary<string, List<EntityType>> TypesHierarchyToAddInObjectContext
{
get
{
if (_typesHierarchyToAddInObjectContext == null)
_typesHierarchyToAddInObjectContext = new Dictionary<string, List<EntityType>>();
return _typesHierarchyToAddInObjectContext;
}
}
private IEnumerable<EntityType> GetSubEntitiesOf(EntityType baseType)
{
var empty = Enumerable.Empty<EntityType>();
if (_typesHierarchyToAddInObjectContext == null)
return empty;
string baseTypeName = baseType.Name;
if (!_typesHierarchyToAddInObjectContext.ContainsKey(baseTypeName))
return empty;
return TypesHierarchyToAddInObjectContext[baseTypeName];
}
private void AddSubEntities(EntityType baseType, EntityType typeToAdd)
{
string baseTypeName = baseType.Name;
if (!TypesHierarchyToAddInObjectContext.ContainsKey(baseTypeName))
TypesHierarchyToAddInObjectContext.Add(baseTypeName, new List<EntityType>());
TypesHierarchyToAddInObjectContext[baseTypeName].Add(typeToAdd);
}
protected override string GetDefaultExtension()
{
return (".Designer" + base.GetDefaultExtension());
}
protected override byte[] GenerateCode(string inputFileContent)
{
byte[] generatedCodeAsBytes = null;
try
{
XElement csdlContent = ExtractCsdlContent(inputFileContent);
if (csdlContent == null)
{
throw new InvalidOperationException("No CSDL content in input file");
}
_objectContext = null;
_entitySetNames = null;
_typesHierarchyToAddInObjectContext = null;
_first = true;
// Determine language for generated code
LanguageOption languageOption = LanguageOption.GenerateCSharpCode;
string fileExtension = base.GetCodeProvider().FileExtension;
if (fileExtension != null && fileExtension.Length > 0)
{
fileExtension = "." + fileExtension.TrimStart(".".ToCharArray());
}
if (fileExtension.EndsWith(".vb", StringComparison.InvariantCultureIgnoreCase))
{
languageOption = LanguageOption.GenerateVBCode;
}
else if (fileExtension.EndsWith(".cs", StringComparison.InvariantCultureIgnoreCase))
{
languageOption = LanguageOption.GenerateCSharpCode;
}
else
{
throw new InvalidOperationException("Unsupported project language. Only C# and VB are supported.");
}
if (base.CodeGeneratorProgress != null)
{
base.CodeGeneratorProgress.Progress(33, 100);
}
EntityClassGenerator classGenerator;
IList<EdmSchemaError> errors = null;
StringWriter codeWriter = new StringWriter(CultureInfo.InvariantCulture);
for (int i = 0; i < 2; i++)
{
using (XmlReader csdlReader = csdlContent.CreateReader())
{
classGenerator = new EntityClassGenerator(languageOption);
classGenerator.OnTypeGenerated += new TypeGeneratedEventHandler(OnTypeGenerated);
classGenerator.OnPropertyGenerated += new PropertyGeneratedEventHandler(OnPropertyGenerated);
errors = classGenerator.GenerateCode(csdlReader, codeWriter);
}
if (! _first)
break;
_first = false;
if (base.CodeGeneratorProgress != null)
{
base.CodeGeneratorProgress.Progress(66, 100);
}
codeWriter.Dispose();
codeWriter = new StringWriter(CultureInfo.InvariantCulture);
}
if (errors != null)
{
foreach (EdmSchemaError error in errors)
{
int line = (error.Line == 0) ? 0 : (error.Line - 1);
int column = (error.Column == 0) ? 0 : (error.Column - 1);
if (error.Severity == EdmSchemaErrorSeverity.Warning)
{
base.GeneratorWarning(0, error.Message, (uint)line, (uint)column);
}
else
{
base.GeneratorError(4, error.Message, (uint)line, (uint)column);
}
}
}
generatedCodeAsBytes = Encoding.UTF8.GetBytes(codeWriter.ToString());
codeWriter.Dispose();
if (base.CodeGeneratorProgress != null)
{
base.CodeGeneratorProgress.Progress(100, 100);
}
}
catch (Exception e)
{
base.GeneratorError(4, e.Message, 1, 1);
generatedCodeAsBytes = null;
}
return generatedCodeAsBytes;
}
private void OnTypeGenerated(object sender, TypeGeneratedEventArgs eventArgs)
{
var entityType = eventArgs.TypeSource as System.Data.Metadata.Edm.EntityType;
if (_first)
{
if (entityType != null)
{
EdmType baseType;
if ((baseType = entityType.BaseType) != null)
{
//System.Windows.Forms.MessageBox.Show("");
while (baseType.BaseType != null)
baseType = baseType.BaseType;
var baseEntityType = baseType as EntityType;
AddSubEntities(baseEntityType, entityType);
}
}
}
else
{
eventArgs.AdditionalAttributes.AddRange(CreateCodeAttributes(eventArgs.TypeSource));
var objectContext = eventArgs.TypeSource as EntityContainer;
if (objectContext != null)
{
_objectContext = objectContext;
var baseEntitySets = _objectContext.MetadataProperties.FirstOrDefault(mp => mp.Name == "BaseEntitySets");
if (baseEntitySets != null)
{
foreach (var entitySet in (ReadOnlyMetadataCollection<EntitySetBase>)baseEntitySets.Value)
{
var derivedBaseEntityType = entitySet.ElementType as EntityType;
if (derivedBaseEntityType != null)
{
EntitySetNames.Add(derivedBaseEntityType.Name, entitySet);
if (_typesHierarchyToAddInObjectContext != null)
foreach (var derivedEntityType in GetSubEntitiesOf(derivedBaseEntityType))
{
string derivedEntityTypeName = derivedEntityType.Name;
var newProp = new CodeMemberProperty { Name = derivedEntityTypeName + "s", Attributes = MemberAttributes.Public | MemberAttributes.Final, Type = new CodeTypeReference("global::System.Linq.IQueryable<" + derivedEntityTypeName + ">") };
newProp.GetStatements.Add(new CodeMethodReturnStatement(new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), _entitySetNames[derivedBaseEntityType.Name].Name), "OfType", new CodeTypeReference(derivedEntityTypeName)))));
eventArgs.AdditionalMembers.Add(newProp);
}
}
}
}
}
}
}
private void OnPropertyGenerated(object sender, PropertyGeneratedEventArgs eventArgs)
{
if (!_first)
eventArgs.AdditionalAttributes.AddRange(CreateCodeAttributes(eventArgs.PropertySource));
}
private IList<CodeAttributeDeclaration> CreateCodeAttributes(MetadataItem item)
{
string xmlns = "http://tempuri.org/AttributeAnnotations";
List<CodeAttributeDeclaration> codeAttributeDeclarations = new List<CodeAttributeDeclaration>();
if (item != null)
{
IEnumerable<MetadataProperty> metadataProperties = item.MetadataProperties.Where(prop => prop.Name.StartsWith(xmlns));
foreach (MetadataProperty metadataProperty in metadataProperties)
{
string metadataPropertyValue = (string)metadataProperty.Value;
if (!String.IsNullOrEmpty(metadataPropertyValue))
{
string[] attributes = metadataPropertyValue.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string attribute in attributes)
{
string attributeName = attribute;
string[] attributeParams = new string[1];
if (attribute.Contains('('))
{
attributeParams = attribute.Split(new char[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries);
attributeName = attributeParams[0];
}
CodeAttributeDeclaration codeAttributeDeclaration = new CodeAttributeDeclaration(attributeName);
foreach (string attributeParam in attributeParams.Skip(1))
{
object attributeParamObj = null;
bool attributeParamBool = false;
if (bool.TryParse(attributeParam, out attributeParamBool))
{
attributeParamObj = attributeParamBool;
}
else
{
attributeParamObj = attributeParam;
}
codeAttributeDeclaration.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(attributeParamObj)));
}
codeAttributeDeclarations.Add(codeAttributeDeclaration);
}
}
}
}
return codeAttributeDeclarations;
}
private XElement ExtractCsdlContent(string inputFileContent)
{
XElement csdlContent = null;
XNamespace edmxns = "http://schemas.microsoft.com/ado/2007/06/edmx";
XNamespace edmns = "http://schemas.microsoft.com/ado/2006/04/edm";
XDocument edmxDoc = XDocument.Load(new StringReader(inputFileContent));
if (edmxDoc != null)
{
XElement edmxNode = edmxDoc.Element(edmxns + "Edmx");
if (edmxNode != null)
{
XElement runtimeNode = edmxNode.Element(edmxns + "Runtime");
if (runtimeNode != null)
{
XElement conceptualModelsNode = runtimeNode.Element(edmxns + "ConceptualModels");
if (conceptualModelsNode != null)
{
csdlContent = conceptualModelsNode.Element(edmns + "Schema");
}
}
}
}
return csdlContent;
}
}