Entity Framework 6 du Code de la première: Comment la graine de données avec un 'circulaire' relation et générées par les magasins colonnes?
Je suis nouveau à l'EF Premier Code, et je suis en train de semences de ma base de données avec des données à l'aide de code-première migrations. J'ai réussi à résoudre plusieurs erreurs jusqu'à présent, mais maintenant je suis coincé et n'ont pas été en mesure de trouver la réponse. J'ai deux problèmes lors de la mise à jour de la base de données à partir de mon code.
J'ai plusieurs objets qui ont de diverses plusieurs-à-plusieurs et un-à-un les relations, et certains ont fini par créer un cercle. Je ne suis pas sûr si cela est la cause du second problème ou pas, quand j'ai essayer de semer la base de données.
- La première erreur que j'ai est:
A dependent property in a ReferentialConstraint is mapped to a store-generated column. Column: 'LicenseId'.
Est-il une manière que je peux utiliser une db id généré une clé étrangère? Est juste l'ordre dans lequel je suis création/insertion d'objets? (voir l'ensemencement de code ci-dessous)
Si je n'utilise pas [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
dans la Licence, j'obtiens une erreur de ne pas pouvoir implicitement insérer un id qui n'est pas généré par la base de données.
public class License : Entity
{
[Key, ForeignKey("Customer")]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int LicenseId { get; set; }
[Required(ErrorMessage = "Date Created name is required")]
public DateTime DateCreated { get; set; }
public virtual ICollection<ProductLicense> ProductLicenses { get; set; } //one License has many ProductLicenses
public virtual Customer Customer { get; set; } //one Customer has one License
}
public class Customer : Entity
{
[Key]
public int CustomerId { get; set;}
[Required(ErrorMessage = "Username is required")]
[Column(TypeName = "nvarchar")]
[MaxLength(500)]
public string Name { get; set; }
public virtual ICollection<User> Users { get; set; } //one Customer has many users
public virtual License License { get; set; } //one Customer has one License
//public virtual ICollection<License> License { get; set; } //one Customer has many Licenses
}
- Si je change la Licence à la Clientèle-être plusieurs-à-plusieurs relations (dont je ne veux pas), je reçois le message d'erreur suivant:
Cannot insert duplicate key row in object 'dbo.Users' with unique index 'IX_Username'.
Ce sont tous mes relations:
Customer -many-> User -many-> Role -many-> Permission -one- ProductLicense <-many- License -one- Customer
Voici le code que j'ai utilisé dans protected override void Seed(DAL.Models.Context context)
, de la création de la de la des objets dans le code et ensuite à l'aide de AddOrUpdate:
//Default Customers - create
var customers = new[]{
new Customer { Name = "cust_a" },
new Customer { Name = "cust_b" },
new Customer { Name = "cust_c" }
};
//Default Licenses - create
var licenses = new[]{
new License { DateCreated = DateTime.Now.AddDays(-3), Customer = customers[0] },
new License { DateCreated = DateTime.Now.AddDays(-2), Customer = customers[1] },
new License { DateCreated = DateTime.Now.AddDays(-1), Customer = customers[2] }
};
//Default ProductLicenses - create, and add default licenses
var productLicenses = new[]{
new ProductLicense { LicenceType = LicenseType.Annual, StartDate = DateTime.Now, License = licenses[0] },
new ProductLicense { LicenceType = LicenseType.Monthly, StartDate = DateTime.Now, License = licenses[1] },
new ProductLicense { LicenceType = LicenseType.PAYG, StartDate = DateTime.Now, License = licenses[2] }
};
//Default Permissions - create, and add default product licenses
var permissions = new[]{
new Permission { Name = "Super_a", ProductLicense = productLicenses[0] },
new Permission { Name = "Access_b", ProductLicense = productLicenses[1] },
new Permission { Name = "Access_c", ProductLicense = productLicenses[2] }
};
//Default Roles - create, and add default permissions
var roles = new[]{
new Role { Name = "Super_a", Permissions = permissions.Where(x => x.Name.Contains("_a")).ToList() },
new Role { Name = "User_b", Permissions = permissions.Where(x => x.Name.Contains("_b")).ToList() },
new Role { Name = "User_c", Permissions = permissions.Where(x => x.Name.Contains("_c")).ToList() }
};
//Default Users - create, and add default roles
var users = new[]{
new User { Username = "user@_a.com", Password = GenerateDefaultPasswordHash(), Salt = _defaultSalt, Roles = roles.Where(x => x.Name.Contains("_a")).ToList() },
new User { Username = "user@_b.co.uk", Password = GenerateDefaultPasswordHash(), Salt = _defaultSalt, Roles = roles.Where(x => x.Name.Contains("_b")).ToList() },
new User { Username = "user@_c.com", Password = GenerateDefaultPasswordHash(), Salt = _defaultSalt, Roles = roles.Where(x => x.Name.Contains("_c")).ToList() }
};
//Default Customers - insert, with default users
foreach (var c in customers)
{
c.Users = users.Where(x => x.Username.Contains(c.Name.ToLower())).ToList();
context.Customers.AddOrUpdate(c);
}
J'ai aussi essayé de changer la première partie à la suite de //Default Customers - create
à
//Default Customers - create and insert
context.Customers.AddOrUpdate(
u => u.Name,
new Customer { Name = "C6" },
new Customer { Name = "RAC" },
new Customer { Name = "HSBC" }
);
context.SaveChanges();
var customers = context.Customers.ToList();
Je serais très heureux d'aider avec cela, afin que je puisse les graines de ma base de données avec les données appropriées.
Merci beaucoup pour votre aide, et désolé pour le long post.
--- Mise à JOUR ---
Après Chris Pratt est une excellente réponse ci-dessous maintenant, je reçois l'erreur suivante:
Conflicting changes detected. This may happen when trying to insert multiple entities with the same key.
Voici mon nouveau code pour le semis et tous les modèles concernés: https://gist.github.com/jacquibo/c19deb492ec3fff0b5a7
Quelqu'un peut-il aider?
OriginalL'auteur tekiegirl | 2014-10-24
Vous devez vous connecter pour publier un commentaire.
L'amorçage peut être un peu compliqué, mais vous avez juste besoin de garder quelques choses à l'esprit:
Rien ajouté avec
AddOrUpdate
seront, bien, ajoutés ou mis à jour. Mais tout le reste sera ajouté, pas mis à jour. Dans votre code, la seule chose que vous êtes à l'aide deAddOrUpdate
estCustomer
.EF ajouter des éléments lors de la
AddOrUpdate
est l'élément ajouté, mais il ignore ces relations, lorsque celui-ci est en cours de mise à jour.Sur cette base, si vous êtes l'ajout de l'objet hiérarchies comme cela, alors vous avez à prendre un peu de soin supplémentaire. Tout d'abord, vous devez appeler
SaveChanges
entre les niveaux de la hiérarchie, et deuxièmement, vous avez besoin de travailler avec id, pas de relations. Par exemple:Maintenant, vous avez toutes vos clients pris en charge, et ils ont chacun aura une valeur de pièce d'identité, d'une manière ou d'une autre. Ensuite, commencer à creuser dans votre hiérarchie:
Vous n'avez pas besoin d'appeler
SaveChanges
si vous avez affaire à des objets de même niveau dans la hiérarchie jusqu'à ce que vous avez défini tous. Toutefois, si vous avez une entité qui fait référence à quelque chose commeLicense
, alors vous voulez l'appelerSaveChanges
de nouveau avant d'ajouter ceux.Aussi, notez que je suis commutateur de réglage de l'id au lieu de la relation. Cette façon de faire vous permettra de mettre à jour la relation la suite, en changeant l'id. Par exemple:
Alors que la suivante serait pas travail:
Bien sûr, vous n'avez pas réellement un
CustomerId
bien surLicense
, mais vous devriez. Tout en EF va automatiquement générer une colonne de tenir la relation sans elle, vous ne pouvez jamais réellement obtenir à la valeur de clé étrangère sans une propriété explicite, et pour plus de raisons que de ce seul fait, être en mesure de travailler avec la clé étrangère est extrêmement bénéfique. Il suffit de suivre cette convention pour tous vos propriétés de référence:La
ForeignKey
attribut n'est pas toujours nécessaire, selon que votre clé étrangère et de référence des noms de propriété aligner à EF conventions pour de telles choses, mais je trouve qu'il est plus facile et moins sujettes à l'erreur d'être explicite sur mes intentions.ce doit être la accepté de répondre, on dirait...
OriginalL'auteur Chris Pratt
Une clé étrangère doit faire référence à une clé candidate de une autre table (généralement le PK, qui peut être DB généré). La FK est dépendante des valeurs dans une autre table et clairement ne peut pas être généré par la table à laquelle il appartient.
Ce que vous cherchez à faire est appelé "Partage de Clé Primaire". Il semble que vous étaient proches - vous avez juste l'ID de génération en arrière et en l'absence d'un
ForeignKeyAttribute
de l'entité.Si
License
est dépendante de l'entité, vous voulez qu'il ressemble à:Si vous le désirez, il peut être utilisé pour
Table Splitting
, où vous divisez le champs d'une seule table DB entre deux ou plusieurs entités (vous pouvez le faire ci-dessus, en spécifiant le nom de la table pour chaque entité soit par l'intermédiaire deTableAttribute
ou FluentAPI appels). Ceci est utile si vous avez un grand champ que vous voulez être en mesure sélective de la charge, par exemple.OriginalL'auteur Moho
Le premier Code migrations ne considère pas à assurer l'intégrité des mises à jour de votre base de données les enregistrements lors de générer un nouveau script de migration pour être appliquée. Vous pourriez avoir à ajouter des commandes SQL dans la (les) méthode de la migration de fichiers par le biais de l'utilisation de Sql("...") les fonctions de mise à jour de base de données actuelle des lignes avant d'essayer d'appliquer votre migration.
Supposons que vous souhaitez appliquer un nouveau referantial contrainte dans une base de données. Vous ne recevez pas un message d'erreur lors de la génération du fichier de migration, même si votre fichier de référence ne contient pas de lignes correspondantes. Mais vous obtenez le message d'erreur 1 (votre premier message) lors de l'exécution du script sur le gestionnaire de paquets de la console.
Pour cela, il vous faut ajouter Sql("INSERT INTO .... ") et/ou Sql("mise à JOUR .....") les commandes en haut de votre le Haut() méthode qui serait de modifier votre base de données actuelle des lignes avec des valeurs correctes.
De même, vous pourriez avoir à supprimer certains enregistrements de la base de données en fonction de vos changements structurels.
OriginalL'auteur aog