Pregunta

Estoy tratando de definir un nuevo tipo y no han tenido mucha suerte para encontrar cualquier información sobre el uso de listas dentro de ellos. Básicamente mi nuevo tipo contendrá dos listas, digamos que x e y del tipo SqlSingle (del tipo definido por el usuario está escrito en C #) es esto posible?

Si no ¿cómo se supone que ir sobre la simulación de un dos listas de una longitud arbitraria en una columna de SQL Server 2008?

Estoy posiblemente va de este por el camino equivocado, pero es el mejor enfoque que se me ocurre en este momento. Cualquier ayuda es muy apreciada.

¿Fue útil?

Solución

Se puede utilizar un List<T> en un UDT CLR - aunque tipos CLR son estructuras, que debe ser inmutable, por lo que un ReadOnlyCollection<T> sería una mejor opción si usted no tiene una razón muy convincente para la mutabilidad. Lo que usted necesita saber en cualquier caso es que SQL no sabrá cómo utilizar la lista en sí; no se puede simplemente exponer el tipo de lista como IList<T> público o IEnumerable<T> y estar en su camino feliz, al igual que sería capaz de hacer en .NET pura.

Por lo general la forma de evitar esto sería exponer una propiedad Count y algunos métodos para llegar a los elementos individuales de la lista.

Además, en este caso, en lugar de mantener dos listas separadas de los casos SqlSingle, que crearía un tipo adicional para representar un solo punto, para que pueda administrar de forma independiente y pasarlo alrededor en SQL si es necesario:

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

El principal tipo sería algo como esto:

[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 necesita SQL para ser capaz de obtener una secuencia de todos los puntos, entonces usted puede agregar un método enumerable con el tipo de secuencia, así:

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

Se podría pensar que es posible utilizar un IEnumerable<T> y / o usar un método de instancia en lugar de una estática, pero ni siquiera se moleste en tratar, no funciona.

Así que la forma en que se puede utilizar el tipo resultante en SQL Server es:

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)

Espero que esto ayude a conseguir que en el camino correcto. UDT puede ser bastante complicado de manejar cuando se está tratando con datos de lista / secuencia.

Tenga en cuenta también que, obviamente, se le tiene que añadir métodos de serialización, métodos constructor, métodos agregados, y así sucesivamente. Puede ser toda una odisea; asegúrese de que ésta es realmente la dirección que desea entrar, porque una vez que comience a agregar columnas UDT puede ser muy difícil hacer cambios si se da cuenta de que usted tomó la decisión equivocada.

Otros consejos

La lista a que se describen son generalmente normalizada - es decir, almacenados en tablas separadas con una línea por artículo - en lugar de tratar de meter en una sola columna. Si usted puede compartir más información sobre lo que está tratando de lograr, tal vez podemos ofrecer más ayuda.

Editar - estructura de la tabla sugerida:

-- 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>
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top