2009-04-23 11 views
2

J'ai créé un type défini par l'utilisateur en .Net 3.5 comme par mon entrée de blog à l'adresse:LINQ to SQL et CLR Types définis par l'utilisateur

http://jwsadlerdesign.blogspot.com/2009/04/this-is-how-you-register.html

Cela fonctionne bien lors de l'utilisation de SQL avec des technologies comme NHibernate.

Cependant, lorsque j'essaie de mapper ma classe LinQ to SQL pour utiliser cette UDT (avec des définitions d'attribut non XML), et je configure la propriété comme énumération. Je n'arrive pas à faire correspondre LinQ à ce type. J'ai essayé Image, Binary, varchar et entier qui semblent tous émettre des erreurs Cast non valides.

En particulier, j'obtiens l'erreur 'Impossible de lancer l'objet de type' ISTD.InstallManager.Common.Classes.SQLUDTTargetType 'pour taper' System.Byte [] 'toute idée ou aide serait grandement appréciée.

James.

Répondre

2

MISE À JOUR: Je me suis récemment heurté à ce problème et j'ai constaté que la solution précédente n'était pas tout à fait complète. Malgré ce que toute la documentation dit, est possible de le faire, mais quelque peu douloureux.

La première étape, pour votre propre commodité, est de mettre en œuvre certains opérateurs de conversion:

public class MyUDT : INullable, IBinarySerialize 
{ 
    // Class implementation would go here 
    // ... 

    public static explicit operator MyUDT(byte[] data) 
    { 
     using (MemoryStream stream = new MemoryStream(data)) 
     { 
      using (BinaryReader reader = new BinaryReader(stream)) 
      { 
       MyUDT result = new MyUDT(); 
       result.Read(reader); 
       return result; 
      } 
     } 
    } 

    public static explicit operator byte[](MyUDT x) 
    { 
     using (MemoryStream ms = new MemoryStream()) 
     { 
      using (BinaryWriter writer = new BinaryWriter(ms)) 
      { 
       x.Write(writer); 
      } 
      return ms.ToArray(); 
     } 
    } 
} 

LINQ to SQL encore à plat refuser de vous donner le champ UDT, peu importe comment vous déclarez la propriété . Donc, vous devez lui donner un champ binaire à la place. Vous n'avez pas besoin d'une procédure stockée ou tout SQL personnalisé pour cela, il suffit d'ajouter une colonne calculée à votre table:

ALTER TABLE MyTable 
ADD UDTField_Data AS CAST(UDTField AS varbinary(len)) 

LEN est quel que soit votre UDT définit dans l'attribut MaxByteSize.

Maintenant, vous pouvez enfin accéder aux données de la colonne. Vous pourriez être tenté d'utiliser votre UDT comme type de retour de la nouvelle propriété, en pensant que Linq to SQL trouvera votre opérateur de conversion et convertira automatiquement à partir du tableau d'octets; ne dérange pas. Linq to SQL décidera qu'il s'agit en fait d'un objet .NET sérialisé et crachera un message à l'effet que "le flux d'entrée n'est pas un format binaire valide". Au lieu de cela, vous avez besoin d'une autre couche de indirection:

private MyUDT udtField; 

[Column(Name = "UDTField_Data", DbType = "varbinary(len)")] 
private byte[] UdtFieldData 
{ 
    get { return (byte[])udtField; } 
    set { udtField = (MyUDT)value; } 
} 

public MyUDT UdtProperty 
{ 
    get { return udtField; } 
    set { udtField = value; } 
} 

Quelques notes à préciser ce qui se passe ici:

  • Les données réelles sur le terrain (udtField) est déclarée comme l'UDT lui-même, pas un tableau d'octets. La raison en est que nous voulons seulement que la conversion se produise lors du chargement ou de l'enregistrement dans la base de données. Si vous deviez convertir le tableau d'octets en UDT chaque fois que vous y accédiez, cela nuirait non seulement aux performances, mais cela entraînerait des incohérences si l'UDT déclarait des champs mutables.
  • La propriété raw byte [] (UdtFieldData) est déclarée privée, donc les consommateurs ne voient que l'UDT lui-même. Linq to SQL le lira toujours tant qu'il aura l'attribut [Column].
  • La propriété UdtFieldDatane déclare pas de propriété de stockage.Ceci est critique. Si vous essayez d'utiliser le champ UDT comme propriété de stockage, vous obtiendrez simplement le même type erreur de conversion.
  • Enfin, la propriété UdtProperty permet aux consommateurs d'accéder aux données. Pour eux, il ressemble à toute autre propriété.

Il est regrettable que vous devez sauter à travers tant de cerceaux pour obtenir ce travail, mais il fonctionne. Vous aurez probablement des difficultés à faire ce genre de massage à travers le concepteur de surfaces Linq, ce qui n'est qu'une des raisons pour lesquelles je ne l'utilise pas; mieux d'écrire les cours vous-même et d'utiliser SqlMetal pour vous aider si nécessaire.