Sto creando una libreria riutilizzabile utilizzando .NET Core (con targeting per .NETStandard 1.4) e sto utilizzando Entity Framework Core (e nuovo per entrambi). Ho una classe di entità che assomiglia a:
public class Campaign
{
[Key]
public Guid Id { get; set; }
[Required]
[MaxLength(50)]
public string Name { get; set; }
public JObject ExtendedData { get; set; }
}
e ho una classe DbContext che definisce il DbSet:
public DbSet<Campaign> Campaigns { get; set; }
(Sto anche usando il pattern di repository con DI, ma non penso che sia rilevante.)
I miei test unitari mi danno questo errore:
System.InvalidOperationException: impossibile determinare la relazione rappresentata dalla proprietà di navigazione "JToken.Parent" di tipo "JContainer". Configurare manualmente la relazione o ignorare questa proprietà dal modello ..
C'è un modo per indicare che questa non è una relazione, ma dovrebbe essere archiviata come una grande stringa?
@ La risposta di Michael mi ha portato in pista ma l'ho implementata in modo leggermente diverso. Ho finito per archiviare il valore come stringa in una proprietà privata e usarlo come "Backing Field". La proprietà ExtendedData ha quindi convertito JObject in una stringa sul set e viceversa su get:
public class Campaign
{
// https://docs.microsoft.com/en-us/ef/core/modeling/backing-field
private string _extendedData;
[Key]
public Guid Id { get; set; }
[Required]
[MaxLength(50)]
public string Name { get; set; }
[NotMapped]
public JObject ExtendedData
{
get
{
return JsonConvert.DeserializeObject<JObject>(string.IsNullOrEmpty(_extendedData) ? "{}" : _extendedData);
}
set
{
_extendedData = value.ToString();
}
}
}
Per impostare _extendedData
come campo di supporto, ho aggiunto questo al mio contesto:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Campaign>()
.Property<string>("ExtendedDataStr")
.HasField("_extendedData");
}
Aggiornamento: la risposta di Darren all'utilizzo di Conversioni valore core EF (nuova a EF Core 2.1 - che non esisteva al momento di questa risposta) sembra essere il modo migliore per procedere a questo punto.
Andando a rispondere a questa in modo diverso.
Idealmente il modello di dominio non dovrebbe avere idea di come siano archiviati i dati. L'aggiunta di campi di supporto e proprietà extra [NotMapped]
sta effettivamente accoppiando il tuo modello di dominio alla tua infrastruttura.
Ricorda: il tuo dominio è re e non il database. Il database viene appena utilizzato per archiviare parti del tuo dominio.
Invece puoi usare il metodo HasConversion()
EF Core sull'oggetto EntityTypeBuilder
per convertire tra il tuo tipo e JSON.
Dati questi 2 modelli di dominio:
public class Person
{
public int Id { get; set; }
[Required]
[MaxLength(50)]
public string FirstName { get; set; }
[Required]
[MaxLength(50)]
public string LastName { get; set; }
[Required]
public DateTime DateOfBirth { get; set; }
public IList<Address> Addresses { get; set; }
}
public class Address
{
public string Type { get; set; }
public string Company { get; set; }
public string Number { get; set; }
public string Street { get; set; }
public string City { get; set; }
}
Ho aggiunto solo gli attributi a cui il dominio è interessato - e non i dettagli a cui il DB sarebbe interessato; IE non c'è [Key]
.
My DbContext ha la seguente IEntityTypeConfiguration
per la Person
:
public class PersonsConfiguration : IEntityTypeConfiguration<Person>
{
public void Configure(EntityTypeBuilder<Person> builder)
{
// This Converter will perform the conversion to and from Json to the desired type
builder.Property(e => e.Addresses).HasConversion(
v => JsonConvert.SerializeObject(v, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }),
v => JsonConvert.DeserializeObject<IList<Address>>(v, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }));
}
}
Con questo metodo puoi separare completamente il tuo dominio dalla tua infrastruttura. Non c'è bisogno di tutto il campo di supporto e proprietà extra.