Home > Enterprise >  EntityFramework (Data Annotations only) Relationship not resolving with ID
EntityFramework (Data Annotations only) Relationship not resolving with ID

Time:04-07

I have the relationship of two classes.

class ClassA {
   [Required]
   int Id { get; set; }

   [Required]
   public int OtherId { get; set; }

   [ForeignKey("OtherId")]
   public ClassB? Other{ get; set; }
}
class ClassB {
   [Required]
   int Id { get; set; }

   public IEnumerable<ClassA> Others { get; set; } = new List<ClassA>();
}

When I insert an object of ClassA I do it like this:

await this.Context.Set<ClassA>().AddAsync(new ClassA() { OtherId = 2 } );
await this.Context.SaveChangesAsync();

This works perfectly on the live database (Azure SQL DB). When I add the class like this and fetch it from the database later on (e.g. literally after the SaveChangesAsync), I get the object, INCLUDING the object ClassA.Other.

When I run the code on an in-memory DB on the other hand, it does not work! The inserting step works, but does NOT validate if the ID (ClassA.OtherId) exists. This means, I can set the ClassA.OtherId to "12345" without any problems, even if I do not have a single entry of ClassB. If I insert a valid ClassA.OtherId it works as well, but when I fetch the object from the database, ClassA.Other is null.

Just to clarify, why I write ClassB? Other instead of ClassB Other. This is only a simplified version of the code, I tested quickly, but in our production environment, we include/exclude certain fields from certain queries for performance reasons. Therefore, it is possible that the property might be null at certain times.

CodePudding user response:

Most In-memory Testdoubles have some flaws in that regard, instead try to use the SQlite Provider, for it behaves more like a real Database

Example for the Configuration:

public static class EfDbContextSqliteBuilderConfigurationFactory
{
    internal static Action<DbContextOptionsBuilder> GetSqliteDatabaseOption()
    {
        const string tempDataBaseFolder = "Database";
        EnsureSqliteTempDatabaseFolderExists(tempDataBaseFolder);

        return c => c.UseSqlite(new SqliteConnection($"DataSource={tempDataBaseFolder}\\{Guid.NewGuid()}.db"));
    }

    private static void EnsureSqliteTempDatabaseFolderExists(string tempDataBaseFolder)
    {
        if (!Directory.Exists(tempDataBaseFolder))
        {
            Directory.CreateDirectory(tempDataBaseFolder);
        }
    }
}
  • Related