0

The following extension works for EF6 alpha2 but stopped working with alpha3 with null reference exception. The failing statement is the EdmxWriter.WriteEdmx(..)

The views pre-generation is performed on a code-first context.

How to achieve pre-generate views using EF6 alpha3?

 public static PreGeneratedViews PreGenerateViews<T>(this T dbContext) where T : DbContext
    {
        Trace.TraceInformation("PreGenerating views");

        //define ef collections
        EdmItemCollection edmItemCollection = null;
        StoreItemCollection storeItemCollection = null;
        StorageMappingItemCollection mappingItemCollection = null;

        //get ef collections
        GetItemCollections(
            GetEdmx(dbContext),
            out edmItemCollection,
            out storeItemCollection,
            out mappingItemCollection);

        IList<EdmSchemaError> errors = null;
        //get the generated views
        Dictionary<string, string> extentViews = GetExtentViews(mappingItemCollection, out errors);


        //return the pregenerated views as string (xml document)
        return new PreGeneratedViews
                   {
                       EdmEntityContainerName = edmItemCollection.GetItems<EntityContainer>().Single().Name,
                       StoreEntityContainerName = storeItemCollection.GetItems<EntityContainer>().Single().Name,
                       HashOverMappingClosure =
                           ReflectionHelper.GetMappingClosureHash(edmItemCollection.EdmVersion,
                                                                  mappingItemCollection),
                       HashOverAllExtentViews =
                           ReflectionHelper.GenerateHashForAllExtentViewsContent(edmItemCollection.EdmVersion,
                                                                                 extentViews),
                       ViewCount = extentViews.Count,
                       Views = CreateViews(extentViews),
                       ViewsEmbeddedResourceName =
                           string.Format("DbContextViews{0}.xml", Guid.NewGuid().ToString("N")),
                   };
    }

    private static XDocument GetEdmx(DbContext dbContext)
    {
        var ms = new MemoryStream();

        using (XmlWriter writer = XmlWriter.Create(ms))
        {
            EdmxWriter.WriteEdmx(dbContext, writer);
        }

        ms.Position = 0;

        return XDocument.Load(ms);
    }

    private static void SplitEdmx(XDocument edmx, out XmlReader csdlReader, out XmlReader ssdlReader,
                                  out XmlReader mslReader)
    {
        // xml namespace agnostic to make it work with any version of Entity Framework
        XNamespace edmxNs = edmx.Root.Name.Namespace;

        XElement storageModels = edmx.Descendants(edmxNs + "StorageModels").Single();
        XElement conceptualModels = edmx.Descendants(edmxNs + "ConceptualModels").Single();
        XElement mappings = edmx.Descendants(edmxNs + "Mappings").Single();

        ssdlReader = storageModels.Elements().Single(e => e.Name.LocalName == "Schema").CreateReader();
        csdlReader = conceptualModels.Elements().Single(e => e.Name.LocalName == "Schema").CreateReader();
        mslReader = mappings.Elements().Single(e => e.Name.LocalName == "Mapping").CreateReader();
    }

    private static void GetItemCollections(XDocument edmx, out EdmItemCollection edmItemCollection,
                                           out StoreItemCollection storeItemCollection,
                                           out StorageMappingItemCollection mappingItemCollection)
    {
        // extract csdl, ssdl and msl artifacts from the Edmx
        XmlReader csdlReader, ssdlReader, mslReader;
        SplitEdmx(edmx, out csdlReader, out ssdlReader, out mslReader);

        // Initialize item collections
        edmItemCollection = new EdmItemCollection(new[] {csdlReader});
        storeItemCollection = new StoreItemCollection(new[] {ssdlReader});
        mappingItemCollection = new StorageMappingItemCollection(edmItemCollection, storeItemCollection,
                                                                 new[] {mslReader});
    }

    private static Dictionary<string, string> GetExtentViews(StorageMappingItemCollection mappingItemCollection,
                                                             out IList<EdmSchemaError> errors)
    {
        Dictionary<EntitySetBase, string> views = ReflectionHelper.GenerateViews(mappingItemCollection, out errors);
        if (errors != null && errors.Any())
        {
            return null;
        }

        var extentViews = new Dictionary<string, string>(views.Count);

        foreach (var kvp in views)
        {
            extentViews.Add(
                GetExtentFullName(kvp.Key),
                kvp.Value.Replace("\r\n", "\n")); // replace accounts for Xml new line normalization
        }

        return extentViews;
    }

    private static string GetExtentFullName(EntitySetBase entitySet)
    {
        return string.Format("{0}.{1}", entitySet.EntityContainer.Name, entitySet.Name);
    }


    private static string CreateViews(Dictionary<string, string> extentViews)
    {
        var sb = new StringBuilder();
        //var embeddedViewsFileName = Path.ChangeExtension(Host.TemplateFile, "xml");
        using (XmlWriter writer = XmlWriter.Create(sb, new XmlWriterSettings
                                                           {
                                                               Indent = true,
                                                               Encoding = Encoding.UTF8
                                                           }))
        {
            writer.WriteStartElement("views");
            foreach (var kvp in extentViews)
            {
                writer.WriteStartElement("view");
                writer.WriteAttributeString("extent", kvp.Key);
                writer.WriteCData(kvp.Value);
                writer.WriteEndElement();
            }

            writer.WriteEndElement();
        }

        return sb.ToString();
    }

    #region Nested type: ReflectionHelper

    private static class ReflectionHelper
    {
        private static readonly Assembly efAssembly = typeof (StorageMappingItemCollection).Assembly;

        private static readonly MethodInfo generateViewsMethodInfo =
            typeof (StorageMappingItemCollection).GetMethod("GenerateEntitySetViews",
                                                            BindingFlags.NonPublic | BindingFlags.Instance);

        private static readonly MethodInfo getMappingClosureHashMethodInfo =
            efAssembly.GetType("System.Data.Entity.Core.Mapping.MetadataMappingHasherVisitor", true)
                .GetMethod("GetMappingClosureHash", BindingFlags.Static | BindingFlags.NonPublic);

        private static readonly MethodInfo generateHashForAllExtentViewsContentMethodInfo =
            efAssembly.GetType("System.Data.Entity.Core.Common.Utils.MetadataHelper", true)
                .GetMethod("GenerateHashForAllExtentViewsContent", BindingFlags.Static | BindingFlags.NonPublic);

        public static Dictionary<EntitySetBase, string> GenerateViews(
            StorageMappingItemCollection mappingItemCollection, out IList<EdmSchemaError> errors)
        {
            errors = null;
            return
                (Dictionary<EntitySetBase, string>)
                generateViewsMethodInfo.Invoke(mappingItemCollection, new object[] {errors});
        }

        public static string GetMappingClosureHash(double schemaVersion,
                                                   StorageMappingItemCollection mappingItemCollection)
        {
            return (string) getMappingClosureHashMethodInfo.Invoke(
                null,
                new object[]
                    {
                        schemaVersion, 
                        // CodeFirst currently creates always one entity container
                        mappingItemCollection.GetItems<GlobalItem>().Single(
                            i => i.GetType().Name == "StorageEntityContainerMapping")
                    });
        }

        public static string GenerateHashForAllExtentViewsContent(double schemaVersion,
                                                                  Dictionary<string, string> extentViews)
        {
            return (string) generateHashForAllExtentViewsContentMethodInfo.Invoke(
                null,
                new object[] {schemaVersion, extentViews});
        }
    }

The stacktrace is the following:

NullReferenceException

  • at: System.Data.Entity.Edm.Serialization.EdmSerializationVisitor.VisitEdmAssociationSet(AssociationSet item)
  • at: System.Data.Entity.Edm.EdmModelVisitor.VisitCollection[T](IEnumerable1 collection, Action1 visitMethod)
  • at: System.Data.Entity.Edm.EdmModelVisitor.VisitAssociationSets(EntityContainer container, IEnumerable`1 associationSets)
  • at: System.Data.Entity.Edm.EdmModelVisitor.VisitEdmEntityContainer(EntityContainer item)
  • at: System.Data.Entity.Edm.Serialization.EdmSerializationVisitor.VisitEdmEntityContainer(EntityContainer item)
  • at: System.Data.Entity.Edm.EdmModelVisitor.VisitCollection[T](IEnumerable1 collection, Action1 visitMethod)
  • at: System.Data.Entity.Edm.EdmModelVisitor.VisitEntityContainers(IEnumerable`1 entityContainers)
  • at: System.Data.Entity.Edm.EdmModelVisitor.VisitEdmModel(EdmModel item)
  • at: System.Data.Entity.Edm.Serialization.EdmSerializationVisitor.Visit(EdmModel edmModel, String namespaceName, String provider, String providerManifestToken)
  • at: System.Data.Entity.Edm.Serialization.EdmSerializationVisitor.Visit(EdmModel edmModel, String provider, String providerManifestToken)
  • at: System.Data.Entity.Edm.Serialization.SsdlSerializer.Serialize(EdmModel dbDatabase, String provider, String providerManifestToken, XmlWriter xmlWriter, Boolean serializeDefaultNullability)
  • at: System.Data.Entity.ModelConfiguration.Edm.Serialization.EdmxSerializer.WriteEdmxRuntime()
  • at: System.Data.Entity.ModelConfiguration.Edm.Serialization.EdmxSerializer.Serialize(DbDatabaseMapping databaseMapping, DbProviderInfo providerInfo, XmlWriter xmlWriter)
  • at: System.Data.Entity.Infrastructure.EdmxWriter.WriteEdmx(DbModel model, XmlWriter writer)
  • at: System.Data.Entity.Infrastructure.EdmxWriter.WriteEdmx(DbContext context, XmlWriter writer)
  • at: **.DbContextPreGenerateViewExtension.GetEdmx(DbContext dbContext)

Thanks!

4

2 回答 2

1

我刚刚提交了工作项867 (35852e8392ad) 的修复程序。它应该修复 NRE。该修复程序应包含在今天的夜间构建中。你可以试一试,让我知道这是否解决了问题?

于 2013-03-05T23:18:29.187 回答
0

这是 Alpha 3 中的一个已知错误

于 2013-03-04T17:20:14.557 回答