6
votes

Spécifiez la colonne / le champ EF Core en lecture seule

J'ai une table SQL Server avec certains champs qui sont définis par la base de données via des valeurs par défaut qui, une fois enregistrées, ne devraient jamais être modifiées à nouveau (par exemple DateCreated ).

Dans le générateur de modèles ou les classes Entity Framework Core 2.1, comment «marquer» un champ comme étant essentiellement en lecture seule? En d'autres termes, je ne veux pas qu'aucun code puisse définir ou écraser ces champs.

En fonction de ma recherche, est-ce que j'ajouterais .HasDatabaseGeneratedOption (DatabaseGeneratedOption.Identity) à la fin de .Property()?

model.DateCreated = new DateTime();
dbContext.SaveChanges() // errors out

Ou puis-je ajouter un [DatabaseGenerated (DatabaseGeneratedOption.Identity)] code > annotation au champ DateCreated ?

public class Doohicky
{
    public DateTime DateCreated {get; set;}
}

Ou y a-t-il un autre moyen entièrement?

Je le veux tel que dans le à l'avenir, si quelqu'un décide d'écrire quelque chose comme ça, une erreur serait générée.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Doohicky>(entity =>
    {
        ... // other fields

        entity.Property(e => e.DateCreated).HasDefaultValueSql("(getdate())");

        ... // other fields
    });
}

Toute analyse serait grandement appréciée.


0 commentaires

3 Réponses :


1
votes
[Required, DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime DateCreated {get; set;}

0 commentaires

0
votes

J'ai fait cela dans le passé avec des propriétés vérifiables telles que DateCreated, DateModified, etc. Cette solution n'est probablement pas idéale pour exclure des propriétés spécifiques dans divers objets (bien que vous puissiez probablement faire quelque chose avec un attribut personnalisé, etc. ).

Je remplace SaveChanges / Async (), puis parcoure tous les objets modifiés que le contexte suit. Tous mes objets utilisent la même classe de base afin que je puisse y parvenir grâce à ce qui suit:

// A collection of property names which should not be updated
var excludedProperties = new[] { "CreatedBy", "CreatedDateUtc" };

foreach (var change in changes)
{
   // If new, do as you'd like

   // If used, ignore date created
   Array.ForEach(excludedProperties, prop =>
   {
      change.Property(prop).IsModified = false;
   });
}

Avec ces objets, je boucle sur eux et définit certaines propriétés vérifiables, ou ignore properties si l'objet n'est pas nouveau. Tout d'abord, j'ai une collection de chaînes qui représentent les noms de propriétés que je souhaite exclure. Je boucle ensuite sur la collection et ignore les propriétés où le nom de la propriété correspond à celui de la collection exclue. Voir ci-dessous:

var changes = ChangeTracker.Entries<BaseEntity>().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified);


0 commentaires

10
votes

La méthode prévue pour EF Core est de définir AfterSaveBehavior à une valeur autre que la valeur par défaut Enregistrer :

Obtient une valeur indiquant si cette propriété peut ou non être modifiée une fois l'entité enregistrée dans la base de données.

Si , alors une exception sera levée si une nouvelle valeur est attribuée à cette propriété après que l'entité existe dans la base de données.

Si , alors toute modification de la valeur de propriété d'une entité qui existe déjà dans la base de données sera ignorée.

Il n'y a pas encore d'API Fluent dédiée, vous devez donc la définir directement via des métadonnées de propriété mutables comme celle-ci:

    .Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Throw); 

Update (EF Core 3.x): À partir d'EF Core 3.0, de nombreuses propriétés comme celle-ci ont été remplacées par des paires de méthodes d'extension Get / Set , donc le code pertinent maintenant se présente comme suit:

entity.Property(e => e.DateCreated)
    .HasDefaultValueSql("(getdate())")
    .Metadata.AfterSaveBehavior = PropertySaveBehavior.Throw; // <-- 


1 commentaires

Cela m'est utile! Je vous remercie!