2010-04-14 4 views
0

Pour mon application ASP.NET MVC 2, j'utilise Entity Framework 1.0 comme couche d'accès aux données (référentiel). Mais j'ai décidé que je veux retourner POCO. Pour la première fois, j'ai rencontré un problème lorsque je voulais obtenir une liste des marques avec leurs logos optionnels. Voici ce que j'ai fait:Linq to Entities et mappage des relations de clé étrangère POCO (1 à 0..1)

public IQueryable<Model.Products.Brand> GetAll() 
    { 
     IQueryable<Model.Products.Brand> brands = from b in EntitiesCtx.Brands.Include("Logo") 
                select new Model.Products.Brand() 
                 { 
                  BrandId = b.BrandId, 
                  Name = b.Name, 
                  Description = b.Description, 
                  IsActive = b.IsActive, 
                  Logo = /*b.Logo != null ? */new Model.Cms.Image() 
                    { 
                     ImageId = b.Logo.ImageId, 
                     Alt = b.Logo.Alt, 
                     Url = b.Logo.Url 
                    }/* : null*/ 
                 }; 
     return brands; 
    } 

Vous pouvez voir dans les commentaires ce que je voudrais réaliser. Cela a bien fonctionné chaque fois qu'un Brand avait un Logo sinon c'est par une exception que vous pouvez assigner une valeur nulle au type int non null (pour Id). Ma solution de contournement consistait à utiliser nullable dans la classe POCO mais ce n'est pas naturel - alors je dois vérifier non seulement si Logo est nul dans ma couche Service ou Contrôleurs et Vues mais surtout pour Logo.ImageId.HasValue. Il n'est pas justifié d'avoir une propriété non nullLogo si l'ID est null.

Quelqu'un peut-il penser à une meilleure solution?

+2

S'il n'est pas valide que Logo soit non nul si ImageId est null, cela indiquerait un problème avec votre base de données sous-jacente. Si votre EF ORM mappe la propriété ImageId de l'objet Logo sur Nullable , c'est parce que la colonne de la base de données accepte les valeurs NULL, mais s'il s'agit d'un champ clé, elle ne doit pas accepter les valeurs NULL. – jeffora

Répondre

0

J'ai une autre solution pour cela. Puisque dans certains cas, l'image (la classe de la propriété Logo) ne peut pas être null et dans certains cas, je peux décider d'ajouter un peu d'héritage à mon modèle de l'image. Voici ce que je l'ai fait:

public class OptionalImage 
{ 
    public long? ImageId 
    { 
     get; 
     set; 
    } 

    [DisplayName("Obraz")] 
    [StringLength(200, ErrorMessage = "Url jest za długi")] 
    [RegularExpression(@".*\.(jpg|gif|png|jpeg|tif|tiff|JPG|GIF|PNG|JPEG|TIF|TIFF)$", ErrorMessage = "Rozszerzenie pliku jest nieprawidłowe. Dopuszczone to: .jpg, .gif, .png, .jpeg, .tif, .tiff")] 
    public string Url 
    { 
     get; 
     set; 
    } 

    [StringLength(200, ErrorMessage = "Tekst alternatywny jest za długi")] 
    [DisplayName("Tekst alternatywny")] 
    public string Alt 
    { 
     get; 
     set; 
    } 
} 

public class Image : OptionalImage 
{ 
    public new long ImageId 
    { 
     get; 
     set; 
    } 
} 

Alors mon dépôt retourne un identifiant annulable seulement pour les objets qui ont 0..1 relation avec l'image - comme marque. Mais un produit qui a une propriété DefaultImage requise utilisera Image sans ID nullable qui correspond à la base de données et à la conception de la logique métier.

La méthode GetAll dans le référentiel ressemble maintenant à ceci (@omoto merci pour la pointe):

public IQueryable<Model.Products.Brand> GetAll() 
    { 
     IQueryable<Model.Products.Brand> brands = from b in EntitiesCtx.Brands 
                let logo = EntitiesCtx.Images.FirstOrDefault(c => c.ImageId == b.Logo.ImageId) 
                select new Model.Products.Brand() 
                 { 
                  BrandId = b.BrandId, 
                  Name = b.Name, 
                  Description = b.Description, 
                  IsActive = b.IsActive, 
                  Logo = new Model.Cms.OptionalImage() 
                    { 
                     ImageId = logo.ImageId, 
                     Alt = logo.Alt, 
                     Url = logo.Url 
                    } 
                 }; 
     return brands; 
    } 

Pour les produits au lieu de new Model.Cms.OptionalImage() je vais utiliser new Model.Cms.Image() et puisque la valeur de ImageId base de données déposée dans ce cas ne peut pas être nul cela fonctionnera bien et tout sera naturel dans les contrôleurs et les vues. Je pense que ce type de solution de contournement convient très bien à mes besoins. Encore si quelqu'un a une meilleure solution, n'hésitez pas à répondre.

1

juste une option

public IQueryable<Model.Products.Brand> GetAll() 
{ 
    IQueryable<Model.Products.Brand> brands = from b in EntitiesCtx.Brands 
               let logo =EntitiesCtx.Logos.First(c=>c.LogoId==b.LogoId); 
               select new Model.Products.Brand() 
                { 
                 BrandId = b.BrandId, 
                 Name = b.Name, 
                 Description = b.Description, 
                 IsActive = b.IsActive, 
                 Logo = /*b.Logo != null ? */new Model.Cms.Image() 
                   { 
                    ImageId = logo.ImageId, 
                    Alt = logo.Alt, 
                    Url = logo.Url 
                   }/* : null*/ 
                }; 
    return brands; 
} 

Je suppose qu'il vaut mieux que de choisir la place brandsXlogos, au lieu de cela, je propose d'utiliser JOIN Permettez-moi s'il vous plaît si vous trouverez ce utile

+0

Merci pour la suggestion - il vaut mieux que coder en dur la chaîne de navigation pour la propriété Logo. –

0

Une option serait être de ne pas autoriser les logos nuls dans la base de données en premier lieu et avoir un logo spécial id = 0 dans la base de données qui est le logo sans logo. Mettez cela sur n'importe quelle marque pour laquelle vous n'avez pas de logo. c'est-à-dire un modèle de valeur nulle. Si vous n'aimez pas avoir un identifiant codé en dur, créez une valeur de bit "IsNullLogo" sur le logo et utilisez-la pour trouver l'identifiant du logo initialement (car il pourrait avoir un ID différent dans la production au développement ...).).

+0

Eh bien, si je n'autorise pas les valeurs nulles dans ma base de données pour Logo, si j'insère 0, je violerai la contrainte de clé étrangère car il n'y a pas d'image avec cet identifiant. Et ajouter et Image avec l'ID 0 juste pour de tels cas n'est certainement pas une bonne solution .. Pensez à permettre aux utilisateurs de gérer les images. Je devrais vérifier partout s'ils n'essaient pas de supprimer ou de mettre à jour mon houx Non. 1. Les choses se gâtent. –

+0

Vous avez un logo de système spécial dans la base de données, donc il n'y a pas de violation. Vous ne laissez pas les utilisateurs manipuler cette image spéciale (ou toute autre image système spéciale). Ce n'est ni rare ni difficile. –

+0

Je sais que c'est une solution courante et justifiée dans de nombreux scénarios. Il est tout simplement plus naturel pour moi de vérifier les valeurs nulles que d'avoir un enregistrement de base de données spécial pour cela. Pourquoi aurais-je besoin de cet enregistrement plutôt que de vérifier si une marque (ou un produit ou autre) n'a pas de logo? Pour ce faire, je ne pense pas que ce soit une bonne solution d'avoir un enregistrement spécial dans DB. Si je veux utiliser une image par défaut pour les marques qui n'ont pas de logos, c'est quelque chose que j'aimerais avoir dans la couche de présentation et non dans la base de données. Donc, je préfère vérifier null. –