Question

J'ai implémenté un héritage table par type dans mon modèle de données (généralement un type BaseEntity avec toutes les informations de base de mes éléments et un type Employer qui hérite de l'élément .AddToEmployer). Tout semble être configuré correctement et lors de l'utilisation d'entités (via ADO.net Data Services ou via Linq to Entities), je peux voir le type AddObject et tout semble aller pour le mieux. Le problème commence lorsque je crée une nouvelle AddToBaseEntity entité et tente de la sauvegarder.

Sur le contexte qui ne semble pas être un élément AddObject("Employer", NewEmployer) (uniquement et AddToBaseEntity(NewEmployer) ou AddToEmployer).

Si j'utilise var NewEmployer = new Employer() j'obtiens un message d'erreur de:

  

Le nom EntitySet "DataEntities.Employer" est introuvable.

Si j'utilise <=> j'obtiens un message d'erreur de:

  

Impossible de déterminer un ordre valide pour les opérations dépendantes. Des dépendances peuvent exister en raison de contraintes de clé étrangère, d'exigences de modèle ou de valeurs générées par le magasin.

Ai-je manqué une étape dans la configuration de l'héritage? Existe-t-il un moyen spécifique de sauvegarder les objets hérités? Qu'est-ce que je fais mal? Je suppose que le problème fondamental est que je devrais avoir un <=>, que dois-je faire pour que cela soit exposé? Il semble étrange que ce ne soit pas une option puisque je peux voir le type d’employeur du côté client et pouvoir faire des choses telles que:

<=> - ce qui semble suggérer que je peux voir le type d'employeur très bien.

Était-ce utile?

La solution 3

J'ai changé plusieurs choses et j'ai réussi à faire en sorte que cela fonctionne. Je ne suis pas particulièrement sûr du problème de base, mais je voulais publier ce que j'ai fait à titre de référence.

Tables reconstruites: j'ai reconstruit les tables en commençant par les colonnes ID / Key et une seule colonne de données.

Suppression des champs d'incrémentation automatique supplémentaires: j'avais un identifiant d'incrémentation automatique sur BaseEntity et sur l'employeur. J'ai supprimé l'ID d'auto-incrémentation de l'employeur et je viens d'avoir la colonne Employer.BaseEntityID et la clé étrangère dans BaseEntity.BaseEntityID. (cela semble avoir été le coupable, mais j’avais l’impression que cela était permis)

Malheureusement, cela a entraîné le problème suivant: les classes énumérées dans le cadre de l'entité ne peuvent pas avoir de propriétés de navigation (toutes les propriétés de navigation doivent se trouver sur l'entité de base), de sorte que l'héritage va se révéler inutilisable pour nos besoins.

Autres conseils

Mon nom est Phani et je travaille dans l'équipe ADO.NET Data Services.

Les méthodes ResolveName et ResolveType permettent de personnaliser les informations de type que le client écrit dans la charge utile envoyée au serveur et comment la charge utile de réponse du serveur est matérialisée.

Ils vous aident à résoudre les types sur le client et sont utiles dans de nombreux scénarios. Voici quelques exemples:

  1. La hiérarchie des types d'entités sur le client est différente de celle du serveur.
  2. Les types d'entités exposés par le service participent à l'héritage et vous souhaitez utiliser des types dérivés sur le client.

<=> est utilisé pour changer le nom de l'entité que nous avons mis en communication lors d'une requête au serveur.

Considérez ce modèle de données: Sur le serveur

public class Employee {
    public int EmployeeID {get;set;}
    public string EmployeeName {get;set;}
}

public class Manager:Employee {
    public List<int> employeesWhoReportToMe {get;set;}
}

Lorsque vous utilisez le client pour travailler avec des instances du type d'entité du responsable, lors de la soumission des modifications au serveur, nous nous attendons à ce que des informations de type soient présentes dans la charge utile lorsque des entités participent à l'héritage.

context.AddObject("Employees",ManagerInstance ); <-- add manager instance to the employees set.
context.SaveChanges();

Cependant, lorsque le client sérialise cette charge, il insère & "Employé &"; comme nom de type ce qui n'est pas ce qui est attendu sur le serveur. Par conséquent, vous devez fournir un résolveur de noms sur le client,

context.ResolveName = delegate(Type entityType){
    //do what you have to do to resolve the type to the right type of the entity on the server
    return entityType.FullName;
}

un résolveur de types est utilisé de la même manière.

context.ResolveType = delegate(string entitySetName){
    //do what you have to do to convert the entitysetName to a type that the client understands
    return Type.GetType(entitySetName);
}

Eh bien, vous n’obtenez qu’un ensemble d’entités pr. classe de base, donc .AddToBaseEntity est la solution en tant que telle.

Mais il semble que votre modèle comporte une dépendance circulaire, de sorte que le cadre Entity ne peut pas déterminer dans quel ordre enregistrer.

Vérifiez que vous avez des clés étrangères à la base sur vos entités dérivées et mettez à jour votre modèle.

L'employeur n'est pas défini comme un ensemble d'entités, mais comme un type d'entité. C'est ainsi qu'il vous manque AddToEntity dans l'objet context. Il y a toujours un ensemble d'entités pour une hiérarchie de classes, dans ce cas il s'agit d'un ensemble d'entités BaseClass.

Si vous souhaitez obtenir le jeu d'entités 'Employeur', vous pouvez essayer de modifier manuellement le fichier edmx et d'ajouter un nouveau jeu d'entités 'Employeur', puis de définir le type d'entité 'Employeur' pour qu'il appartienne à ce jeu d'entités. Cela ne devrait pas être difficile, je l’ai souvent fait.

Je ne sais pas s'il existe une solution plus régulière.

Venant plus de deux ans plus tard, mais dans l’intérêt de rester pertinent pour le trafic de recherche, voici une façon de contourner ce problème rapidement dans une classe de commodité que nous utilisions pour remplir rapidement notre base de données avec des données de transfert.

Vous n'êtes pas sûr des versions précédentes, mais Entity Framework 4 vous permet de vider l'objet dans le contexte en tant qu'objet de base, puis le cadre détermine les références côté serveur. Ainsi, vous n’utiliseriez pas AddToInheritedObjects () (qui est de toute façon déconseillé), mais plutôt la méthode ObjectSet & Lt; & Gt; .Add ().

Voici un exemple de classe d'assistance:

public ContextHelper
{
        …
        _context = ModelEntities();

        public T Create<T>() where T : class
        {
            // Create a new context
            _context = new ModelEntities();

            // Create the object using the context (can create outside of context too, FYI)
            T obj = _context.CreateObject<T>();

            // Somewhat kludgy workaround for determining if the object is
            // inherited from the base object or not, and adding it to the context's
            // object list appropriately.    
            if (obj is BaseObject)
            {
                _context.AddObject("BaseObjects", obj);
            }
            else
            {
                ObjectSet<T> set = _context.CreateObjectSet<T>();
                set.AddObject(obj);
            }

            return obj;
        }
        …
}

Ainsi, en supposant que vous ayez les éléments suivants:

class ObjectOne : BaseObject {}
class ObjectTwo {}

Vous pouvez facilement ajouter des entités au contexte:

ContextHelper ch = ContextHelper()
ObjectOne inherited = ch.Create<ObjectOne>();
ObjectTwo toplevel = ch.Create<ObjectTwo>();
…

N'oubliez pas, bien sûr, que ContextHelper doit avoir une méthode publique Save () qui appelle _context.SaveChanges () - ou que vous devez disposer d'un autre moyen de pousser les modifications d'objet jusqu'au magasin de données.

Cela ne constitue peut-être pas une réponse directe à une question donnée sur l'héritage, mais donne, espérons-le, un point de départ aux personnes pour répondre à des questions spécifiques.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top