Question

Je suis en train de définir un nouveau type et n'ont pas eu beaucoup de chance de trouver des informations sur l'utilisation des listes en leur sein. Au fond de mon nouveau type contiendra deux listes, permet de dire que x et y de type SqlSingle (l'utilisateur type défini est écrit en C #) est-ce encore possible?

Sinon, comment êtes-vous censé aller sur la simulation d'un deux listes d'une longueur dans un SQL arbitraire serveur colonne 2008?

Je vais peut-être sur ce mal, mais il est la meilleure approche que je peux penser en ce moment. Toute aide est très appréciée.

Était-ce utile?

La solution

Vous pouvez utiliser un List<T> dans un UDT CLR - même si les types CLR sont struct, qui devrait être immuable, donc un ReadOnlyCollection<T> serait un meilleur choix si vous n'avez pas une raison très convaincante pour la mutabilité. Ce que vous devez savoir dans les deux cas est que SQL ne saura pas comment utiliser la liste elle-même; vous ne pouvez pas simplement exposer le type de liste en tant que IList<T> public ou IEnumerable<T> et être sur votre petit bonhomme de chemin, comme vous seriez en mesure de le faire dans .NET pur.

En général, la façon de contourner ce serait d'exposer une propriété Count et quelques méthodes pour obtenir les éléments de liste.

En outre, dans ce cas, au lieu de maintenir deux listes distinctes d'instances de SqlSingle, je créerais un autre type pour représenter un seul point, de sorte que vous pouvez le gérer de façon indépendante et le transmettre autour de SQL si vous devez:

[Serializable]
[SqlUserDefinedType(Format.Native)]
public struct MyPoint
{
    private SqlSingle x;
    private SqlSingle y;

    public MyPoint()
    {
    }

    public MyPoint(SqlSingle x, SqlSingle y) : this()
    {
        this.x = x;
        this.y = y;
    }

    // You need this method because SQL can't use the ctors
    [SqlFunction(Name = "CreateMyPoint")]
    public static MyPoint Create(SqlSingle x, SqlSingle y)
    {
        return new MyPoint(x, y);
    }

    // Snip Parse method, Null property, etc.
}

Le principal type ressemblerait à quelque chose comme ceci:

[Serializable]
[SqlUserDefinedType(Format.UserDefined, IsByteOrdered = true, MaxByteSize = ...)]
public struct MyUdt
{
    // Make sure to initialize this in any constructors/builders
    private IList<MyPoint> points;

    [SqlMethod(OnNullCall = false, IsDeterministic = true, IsPrecise = true)]
    public MyPoint GetPoint(int index)
    {
        if ((index >= 0) && (index < points.Count))
        {
            return points[index];
        }
        return MyPoint.Null;
    }

    public int Count
    {
        get { return points.Count; }
    }
}

Si vous avez besoin SQL pour être en mesure d'obtenir une séquence de tous les points, vous pouvez ajouter une méthode dénombrable au type de séquence ainsi:

[SqlFunction(FillRowMethodName = "FillPointRow",
    TableDefinition = "[X] real, [Y] real")]
public static IEnumerable GetPoints(MyUdt obj)
{
    return obj.Points;
}

public static void FillPointRow(object obj, out SqlSingle x, out SqlSingle y)
{
    MyPoint point = (MyPoint)obj;
    x = point.X;
    y = point.Y;
}

Vous pourriez penser qu'il est possible d'utiliser un IEnumerable<T> et / ou utiliser une méthode d'instance au lieu d'une statique, mais ne prend pas la peine d'essayer, ça ne fonctionne pas.

Ainsi, la façon dont vous pouvez utiliser le type résultant dans SQL Server est:

DECLARE @UDT MyUdt
SET @UDT = <whatever>

-- Will show the number of points
SELECT @UDT.Count

-- Will show the binary representation of the second point
SELECT @UDT.GetPoint(1) AS [Point]

-- Will show the X and Y values for the second point
SELECT @UDT.GetPoint(1).X AS [X], @UDT.GetPoint(1).Y AS [Y]

-- Will show all the points
SELECT * FROM dbo.GetPoints(@UDT)

Espérons que cela vous aide à obtenir sur la bonne voie. UDT peut être assez compliqué à gérer quand ils traitent des données liste / séquence.

Notez également que vous aurez besoin évidemment d'ajouter des méthodes de sérialisation, les méthodes de constructeur, les méthodes globales, et ainsi de suite. Il peut être tout à fait une épreuve; assurez-vous que ce soit réellement la direction que vous voulez aller, car une fois que vous commencez à ajouter des colonnes UDT, il peut être très difficile de faire des changements si vous vous rendez compte que vous avez fait le mauvais choix.

Autres conseils

Les listes que vous décrivez sont généralement normalisées - à savoir, stockées dans des tables séparées avec une ligne par article - plutôt que d'essayer de les entasser dans une seule colonne. Si vous pouvez partager plus d'informations sur ce que vous essayez d'accomplir, nous pouvons peut-être offrir une assistance plus.

Modifier - structure de la table suggérée:

-- route table--
route_id      int   (PK)
route_length  int (or whatever)
route_info    <other fields as needed>

-- waypoint table --
route_id      int      (PK)
sequence      tinyint  (PK)
lat           decimal(9,6)
lon           decimal(9,6)
waypoint_info <other fields as needed>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top