Pergunta

Estou tentando definir um novo tipo e não tive muita sorte em encontrar nenhuma informação sobre o uso de listas nelas. Basicamente, meu novo tipo conterá duas listas, digamos x e y do tipo sqlsingle (o tipo definido pelo usuário está escrito em C#) Isso é possível?

Se não, como você deve simular duas listas de um comprimento arbitário em uma coluna SQL Server 2008?

Estou possivelmente fazendo isso da maneira errada, mas é a melhor abordagem que consigo pensar no momento. Qualquer ajuda é muito apreciada.

Foi útil?

Solução

Você pode usar um List<T> em um clr udt - embora os tipos de CLR sejam estruturas, o que deve ser imutável, então um ReadOnlyCollection<T> Seria uma escolha melhor se você não tiver uma razão muito atraente para a mutabilidade. O que você precisa saber em ambos os casos é que o SQL não saberá como usar a própria lista; Você não pode simplesmente expor o tipo de lista como um público IList<T> ou IEnumerable<T> E esteja no seu caminho alegre, como você seria capaz de fazer no .NET puro.

Normalmente a maneira de contornar isso seria expor um Count Propriedade e alguns métodos para obter os itens de lista individuais.

Além disso, neste caso, em vez de manter duas listas separadas de SqlSingle Instâncias, eu criaria um tipo adicional para representar um único ponto, para que você possa gerenciá -lo de forma independente e passá -lo no SQL se precisar:

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

O tipo principal seria algo assim:

[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 você precisar do SQL para obter uma sequência de todos os pontos, também poderá adicionar um método enumerável ao tipo de sequência:

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

Você pode pensar que é possível usar um IEnumerable<T> e/ou use um método de instância em vez de estático, mas nem se preocupe em tentar, não funciona.

Portanto, a maneira como você pode usar o tipo resultante no 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)

Espero que isso ajude a colocá -lo no caminho certo. Os UDTs podem ficar bastante complicados de gerenciar quando estão lidando com dados de lista/sequência.

Observe também que você obviamente precisará adicionar métodos de serialização, métodos do construtor, métodos agregados e assim por diante. Pode ser uma provação e tanto; Certifique -se de que essa é realmente a direção que você deseja seguir, porque depois de começar a adicionar colunas UDT, pode ser muito difícil fazer alterações se você perceber que fez a escolha errada.

Outras dicas

As listas que você descrevem geralmente são normalizadas - ou seja, armazenadas em tabelas separadas com uma linha por item - em vez de tentar colocá -las em uma única coluna. Se você pode compartilhar mais informações sobre o que está tentando realizar, talvez possamos oferecer mais assistência.

Editar - Estrutura da tabela 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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top