Domanda

Sto cercando di definire un nuovo tipo e non hanno avuto molta fortuna trovare tutte le informazioni su come utilizzare gli elenchi al loro interno. Fondamentalmente il mio nuovo tipo conterrà due liste, consente di dire xey di tipo SqlSingle (tipo definito dall'utente è scritto in C #) è anche possibile?

Se non come si fa ad andare sulla simulazione di un due liste di lunghezza arbitraria in una colonna di SQL Server 2008?

Sto forse andare su questo nel modo sbagliato, ma è l'approccio migliore che posso pensare in questo momento. Qualsiasi aiuto è molto apprezzato.

È stato utile?

Soluzione

È possibile utilizzare un List<T> in un CLR UDT - anche se i tipi CLR sono le strutture, che dovrebbero essere immutabili, quindi un ReadOnlyCollection<T> sarebbe una scelta migliore se non si dispone di un motivo molto convincente per la mutevolezza. Quello che dovete sapere in entrambi i casi è che SQL non saprà come utilizzare la lista stessa; Non è possibile esporre semplicemente il tipo di lista come IList<T> pubblico o IEnumerable<T> e sul vostro modo allegro, come si sarebbe in grado di fare in puro NET.

In genere il modo per aggirare il problema sarebbe quello di esporre una proprietà Count e alcuni metodi per ottenere le singole voci di elenco.

Inoltre, in questo caso, invece di mantenere due liste separate di casi SqlSingle, mi creerebbe un ulteriore tipo di rappresentare un unico punto, in modo da poter gestire in modo indipendente e passarlo in giro in SQL se avete bisogno di:

[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.
}

Il principale tipo sarebbe simile a questa:

[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; }
    }
}

Se è necessario SQL per essere in grado di ottenere una sequenza di tutti i punti, quindi è possibile aggiungere un metodo enumerabile al tipo di sequenza così:

[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;
}

Si potrebbe pensare che è possibile utilizzare un IEnumerable<T> e / o utilizzare un metodo di istanza al posto di uno statico, ma non si preoccupano neppure di provare, non funziona.

Quindi il modo è possibile utilizzare il tipo con conseguente SQL Server è:

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)

Spero che questo ti aiuta a ottenere sulla strada giusta. UDT può ottenere abbastanza complicato da gestire quando hanno a che fare con i dati lista / sequenza.

Si noti inoltre che avrete ovviamente bisogno di aggiungere metodi di serializzazione, i metodi, i metodi costruttore aggregati, e così via. Può essere piuttosto un calvario; fare in modo che questo è in realtà la direzione si vuole andare in, perché una volta che si avvia l'aggiunta di colonne UDT può essere molto difficile apportare modifiche se ti rendi conto che hai fatto la scelta sbagliata.

Altri suggerimenti

Liste come lei di solito sono normalizzati - che è, memorizzati in tabelle separate con una riga per ogni elemento - piuttosto che cercare di loro stipare in una singola colonna. Se è possibile condividere più informazioni su ciò che si sta cercando di realizzare, forse siamo in grado di offrire maggiore assistenza.

Modifica - struttura della tabella suggerito:

-- 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>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top