-1

I'm writing an Azure Function that subscribes to an event grid and performs actions against an Azure SQL database on every event it receives. The event grid has events published to it when a create error occurs in one system "SecondAppName" that was triggered by another system "Appname". Basically, an entity gets created in one system then an analagous entity gets created in the other (also via event grid publishes/subscribers). This function app looks for failures in creations in the second system so it can retrigger the create. This is not nearly complete but I'm at a roadblock

I'm using Entity Framework 6 (Database First) to read and write from the database. When trying to query a project using Entity Framework FindAsync(), the result is brought back as null. Here is the relevant code with names from my organization obscured:

#r "Newtonsoft.Json"
#r "System.Configuration"
#r "System.Data"
#r "System.Data.Common"

using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections;
using System.Configuration;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Data.Entity.SqlServer;
using System.Data.SqlClient;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;

public static async Task Run(JObject eventGridEvent, TraceWriter log)
{
    log.Info($"event was: {eventGridEvent.ToString(Formatting.Indented)}");
    var eventGridEventProperties = eventGridEvent.Properties().ToList();
    if(
        eventGridEventProperties.Count(
            prop => prop.Name == "eventType" && prop.Value.ToString() == "error"
        ) > 0 &&
        eventGridEventProperties.Count(
            prop => prop.Name == "subject" && prop.Value.ToString() == "/appname/subject1"
        ) > 0
    )
    {
        var appnameSecondAppNameErrorEvent = eventGridEvent.ToObject<AppnameSecondAppNameErrorEvent>();
        var entityId = appnameSecondAppNameErrorEvent.Data.EntityId;
        log.Info($"subject1 create event error found for UAT Entity {entityId}");
        log.Info($"trying to query entity data for UAT Entity {entityId}");

        try
        {
            string connectionString = ConfigurationManager.ConnectionStrings["AppnameContext"].ToString();
            using (var _appnameContext = new AppnameDbContext(connectionString))
            {
                var entity = await _appnameContext.Entity.FindAsync(entityId)
                // var enitty = await _appnameContext
                //     .Entity
                //     .SqlQuery("select * from Entity where EntityId=@id", new SqlParameter("@id", entityId))
                //     .FirstOrDefaultAsync();

                if(entity != null)
                {
                    log.Info(
                        $@"Entity was Id: {entity.EntityId}, 
                           Name: {entity.Name}, 
                           Property1: {entity.Property1Name}, 
                           Property2Name: {entity.Property2Name}"
                    );
                }
                else
                {
                    throw new Exception($"UAT Entity {entityId} not found");
                }

            }
        }
        catch (Exception ex)
        {
            log.Info($"Error getting Appname UAT Entity {entityId} with reason: {ex.Message}");
        }
    }
}

public class AppnameSecondAppNameErrorEvent
{
    public Guid Id { get; set; }
    public string Subject { get; set; }
    public string EventType { get; set; }
    public DateTime EventTime { get; set; }
    public AppnameSecondAppNameErrorEventData Data { get; set; }
    public string DataVersion { get; set; }
    public string MetaDataVersion { get; set; }
    public string Topic { get; set; }
}

public class AppnameSecondAppNameErrorEventData
{
    public Guid EntityId { get; set; }
    public string ErrorMessage { get; set; }
}

public class AppnameDbContext : DbContext
{
    public AppnameDbContext(string cs) : base(cs) { }
    public DbSet<Entity> Entity { get;set; }
}

public class Entity
{
    [Key]
    public Guid EntityId { get; set; }
    public string Name { get; set; }
    public string Property1Name { get; set; }
    public string Property2Name { get; set; }
}

It always throws that exception "UAT Entity Not Found ... " because the entity is always null

I know it's not a connection issue, because the commented out lines of code that run the manual SQL query bring back the result. That also means that the result exists in the database as well. Furthermore, if I run the lines like this:

 var entity = await _appnameContext
                        .Entity
                        .SqlQuery("select * from Entity where EntityId=@id", new SqlParameter("@id", entityId))
                        .FirstOrDefaultAsync();
var entity2 = await _appnameContext.Entity.FindAsync(entityId);

entity2 has the result in it, so it's getting attached to the context.

What am I doing wrong here? If I have to manually run a SQL query to get this to work I might as well not even use Entity Framework

Here is some more relevant info about the function app:

project.json:

{
    "frameworks": {
        "net46":{
            "dependencies": {
                "EntityFramework": "6.1.2",
                "System.Data.Common": "4.3.0"
            }
        }
    }
}

Connection String in function app settings (with organization details and credentials obscured):

Server=tcp:server.database.windows.net,1433;Initial Catalog=DATABASE;Persist Security Info=False;User ID=username;Password=password;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;

The user to that database is the administrator.

And here is an example of what the event that comes in looks like:

{
    "id": "621ed36b-13df-4af3-af45-3cff2434cea7",
    "subject": "/appname/subject1",
    "eventType": "error",
    "eventTime": "2018-08-14T17:30:59.4395766Z",
    "data": {
        "entityId": "67d14894-1a0c-4c6d-b091-544260d89642",
        "errorMessage": "Error creating the entity"
    },
    "dataVersion": "",
    "metadataVersion": "1",
    "topic": "/subscriptions/..."
}

Finally it's worth noting I am not using Visual Studio to program this, I am using the Azure Portal's web interface to do so.

Thanks for any help or advice!

pdaniels0013
  • 411
  • 1
  • 5
  • 14
  • When you use http://www.sqlcoffee.com/Azure_0010.htm what SQL is being executed by your non-working EF query? – mjwills Aug 16 '18 at 23:13

1 Answers1

0

I found the issue. Somehow, Entity Framework preformed a code first migration and added another table called "Entity1" that it was querying from instead. To fix this, I deleted the new table, and added the data annotation [Table("Entity")] above my Entity class

pdaniels0013
  • 411
  • 1
  • 5
  • 14
  • As a side note, unrelated to the answer, I strongly recommend doing Azure Function development in Visual Studio, and letting your entity framework context be generated with Visual Studio tools should you be using an existing database. That's the lesson I learned through this struggle – pdaniels0013 Aug 17 '18 at 20:01